0

我想在不傳遞任何「內核」容器的情況下使用基於工廠的依賴注入,這樣就無法實例化一個類,而不必從「頂部」明確傳遞它的依賴關係。構造函數的自動工廠生成器DI​​

手動方式,這樣做需要在引導這樣的代碼:

static void Main(string[] args) 
    { 
     // simplified example, can require classes in reality 
     ABFactory abFactory = (data1) => new AB(data1); 
     ACAFactory acaFactory = (data1) => new ACA(data1); 
     ACFactory acFactory = (x) => new AC(x, acaFactory); 
     IA a = new A(1, new AA(1, new AAA(), new AAB()), abFactory, acFactory); 
     a.Action(123); 
    } 

當工廠是指

delegate IAB ABFactory(string data1); 
delegate IAC ACFactory(int x); 
delegate IACA ACAFactory(int data1); 

有什麼我可以使用,使工廠建設更容易,甚至自動?有不同的工廠類型支持(池,ThreadLocal緩存等)?

UPDATE

一些實際的代碼示例:

public interface IItemSetSpawnController 
{ 
    void TransitSpawned(); 
} 

public class ItemSetSpawnController : IItemSetSpawnController 
{ 
    readonly GameMap.ItemSet _set; 
    readonly LootableFactoryDelegate _lootableFactory; 
    readonly IFiber _fiber; 

    readonly int _defaultRespawnTime; 

    public ItemSetSpawnController([NotNull] GameMap.ItemSet set, int defaultRespawnTime, [NotNull] LootableFactoryDelegate lootableFactory, IFiber fiber) 
    { 
     if (set == null) throw new ArgumentNullException(nameof(set)); 
     if (lootableFactory == null) throw new ArgumentNullException(nameof(lootableFactory)); 
     if (set.Items.Count == 0) throw new ArgumentException("Empty set", nameof(set)); 
     _set = set; 
     _lootableFactory = lootableFactory; 
     _fiber = fiber; 
     _defaultRespawnTime = defaultRespawnTime; 
    } 

    public void TransitSpawned() 
    { 
     // Fiber.Schedule for respawning 
    } 
} 

public delegate IItemSetSpawnController ItemSetSpawnControllerFactory(
    [NotNull] GameMap.ItemSet set, int defaultRespawnTime, [NotNull] LootableFactoryDelegate lootableFactory, IFiber fiber); 


protected virtual void AddMapLootables() 
{ 
    foreach (var set in ItemSets) 
    { 
     if (set.Items.Count == 0) continue; 
     var c = ItemSetSpawnControllerFactory(
      set, 
      Settings.LootRespawnTime, 
      LootableFactory, 
      ExecutionFiber); 
     c.TransitSpawned(); 
    } 

} 
+1

Autofac內置這個概念:http://docs.autofac.org/en/latest/advanced/delegate-factories.html –

回答

0

在我看來,你的組件與運行時數據初始化。這是bad practice,因爲這會使你的DI配置複雜化很多,我認爲你的情況就是這樣。

而不是使用工廠初始化組件的構造函數依賴於服務依賴性和運行時數據的組件,將運行時數據移出構造函數並在運行時將其提供給組件。您可以通過將運行時值傳遞給組件的方法來完成此操作,也可以將組件注入到允許組件在運行時(初始化後)請求該值的組件中。

要選擇哪個選項取決於使用運行時值是否是實現細節。如果它是抽象的重要部分,則該值應該是抽象方法簽名的一部分。如果抽象無關緊要,並且只有組件本身應該瞭解它,那麼注入允許訪問此運行時值的服務是最明顯的解決方案。

UPDATE

如果將運行時數據出來的構造函數,你將能夠去除需要使用的工廠作爲抽象的附加層,你可以將代碼更改爲類似這樣:

public interface IItemSetSpawnController { 
    void TransitSpawned(GameMap.ItemSet set); 
} 

public class ItemSetSpawnController : IItemSetSpawnController { 
    readonly LootableFactoryDelegate _lootableFactory; 
    readonly IFiber _fiber; 
    readonly ISessings settings; 
    public ItemSetSpawnController(ISessings settings, 
     [NotNull] LootableFactoryDelegate lootableFactory, IFiber fiber) { 
     _lootableFactory = lootableFactory; 
     _fiber = fiber; 
     _settings = settings; 
    } 
    public void TransitSpawned([NotNull] GameMap.ItemSet set) { 
     if (set == null) throw new ArgumentNullException(nameof(set)); 
     // If LootRespawnTime is a config value that doesn't change after startup, you 
     // can more it back into the constructor of the controller. 
     int defaultRespawnTime = _settings.LootRespawnTime; 
     // Fiber.Schedule for respawning 
    } 
} 

class MapLooter { 
    IItemSetSpawnController controller; 
    public MapLooter(IItemSetSpawnController controller){ 
     this.controller = controller; 
    } 
    public void AddMapLootables() { 
     foreach (var set in ItemSets) { 
      if (set.Items.Count == 0) continue; 
      this.controller.TransitSpawned(set); 
     } 
    } 
} 
+0

是的,這是一種常用的方法 - 將上下文數據傳遞給構造函數。實際上,如果一個類沒有上下文實例化,那麼它應該是單例。我明白,你建議將這樣的上下文初始化代碼移動到一個單獨的方法包括接口,但它看起來有點奇怪... – Vlad

+0

@Vlad:如果您更新您的問題,並使您的代碼更具體(與實際名稱您正在嘗試創建的抽象和組件),我可以舉一個如何改進設計的具體示例。 – Steven

+0

好的,我更新了它 – Vlad

相關問題