2016-07-05 66 views
7

我有一個(增長的)數據生成器列表。我需要的生成器是由工廠類創建的。生成器都實現了一個通用接口,其中包括一個靜態字符串name工廠模式,按屬性選擇

我想要做的是:用上述名字的字符串參數調用factory.Create方法。 create方法找到具有該名稱的生成器並返回該生成器的新實例。

在我看來這樣做的獎勵:我只需要添加新的生成器類,而無需編輯工廠。

問:

  1. 這是處理這個問題的好辦法?
  2. 我怎樣才能找到所有的發電機?反映每個接口/名稱空間的每個成員(對於生成器+它們的接口都是唯一的)的實現?
  3. 稱這種工廠工作方式是正確的,還是這種不同的模式?

最後,我會打電話的工廠像這樣(簡化):

//Caller 
public DataModel GetData2() 
{ 
    var generator = new DataFactory().Create("Gen.2"); 
    return generator.GetData(); 
} 

//Factory 
public class DataFactory 
{ 
    public AbstractDataGenerator Create(string type) 
    { 
     //Here the magic happens to find all implementations of IDataGenerator 
     var allGenerators = GetImplementations(); 
     var generator = allGenerators.FirstOrDefault(f => f.name == type); 
     if (generator != null) 
      return (AbstractDataGenerator)Activator.CreateInstance(generator); 
     else 
      return null; 
    } 
} 

//Interface 
public abstract class AbstractDataGenerator 
{ 
    public static string name; 
    public abstract DataModel GetData(); 
} 

//Data-Generators 
public class DataGen1 : AbstractDataGenerator 
{ 
    public static string name = "Gen.1"; 
    public DataModel GetData() 
    { 
     return new DataModel("1"); 
    } 
} 
public class DataGen2 : AbstractDataGenerator 
{ 
    public static string name = "Gen.2"; 
    public DataModel GetData() 
    { 
     return new DataModel("2"); 
    } 
} 

應在工廠魔術GetImplementations()通過反射來完成,或者以某種方式有什麼不同?我應該使用完全不同的方法嗎?

由於答案涉及IoC和DI:該項目已經使用NInject,因此它將可用。 從接口切換到抽象類。

+0

一個問題我已經使用這種方法發現的是,爲了獲得發電機的「名稱」屬性,你_need的object_的一個實例。 – stuartd

+0

這就是爲什麼我使屬性靜態。如果我沒有弄錯,這應該刪除一個實例的需要。 – MilConDoin

+0

接口不能有靜態成員.. – stuartd

回答

4

這是處理這個問題的好方法嗎?

擁有一個工廠來獲得您需要的邏輯類的一個實例 - 我相信這是一個好方法。這是我自己使用很多的模式。關於你有沒有密鑰的方式 - 我寧願不要將它作爲一個static成員(不管接口不能有靜態成員),而只是作爲property,並向IDataGenerator添加基類。該基類將有一個構造函數,將得到name - 這樣你創建的每個新的DataGenerator將不得不設置它,你不會忘記。


關於具有namestring - 我個人比較喜歡擁有它「強類型」。我的意思是,如果我通過Gen . 2而不是Gen.2與字符串我只會在運行時發現此問題。其它可能的方式(如果你想,因爲一個簡單的字符串也沒關係 - 品味問題):

  • enum
  • 替換字符串與您的所有值靜態只讀字符串靜態類 - 那麼在你的代碼中使用這些值。你得到了intellisense的好處,並且沒有弄錯字符串,但比enum更好 - 你仍然可以傳遞不在「列表」中的字符串,因此你可以添加新的字符串作爲附加組件。
  • 有一個RequestGenerator的對象,每個GeneratorIDataGenerator<TGeneratorRequest>。這可能是一種矯枉過正,但如果你還需要額外的信息來創建一個不同的DataGenerator然後考慮它。

我怎樣才能找到所有的發電機?反映每個接口/名稱空間的每個成員(對於生成器+它們的接口都是唯一的)的實現?

是的,反射可以是一個很好的方法。不過,我建議讀入Dependency InjectionIoC Containers,例如Castle Windsor。有些事情在那裏,已經實現了它的你,爲什麼要重新發明輪子:)

DI在我看來是一個生命換概念

是否正確調用這種工作方式一個工廠,還是這種不同的模式?

Yap。這是一個Factory

應該通過反射或以某種不同的方式在工廠中的魔術GetImplementations()?對於問題

查看答案2

+0

您的附加構思包含靜態常量字符串的靜態類已經實現:)我在上面的例子中使用了魔術字符串,而不是簡單的。 – MilConDoin

+0

好:)。我也會說,爲工廠選擇「關鍵」的方式因代碼的暴露方式而有所不同。如果它隱藏在門面之後,並且是您自己的實現細節,那麼它對於哪個選項無關緊要。然而,如果它暴露給外部使用,我更喜歡'enum'或'TRequest'選項 - 對於其他人來說,比'string'更清晰的界面 –

2

這是構造函數注入可以真正發光的地方。研究依賴注入工具並僱用一個!它也檢查你的「獎金」請求。

這是你的工廠可能會是什麼樣構造器注入:

public class DataFactory 
{ 
    private Dictionary<string, IDataGenerator> generators; 

    public DataFactory(IDataGenerator[] generatorReferences) 
    { 
     this.generators = generatorReferences 
      .ToDictionary(k => k.name, v => v); 
    } 
    public IDataGenerator Create(string type) 
    { 
     IDataGenerator generator = null; 
     this.generators.TryGetValue(type, out generator); 
     return generator; 
    } 
} 

大多數DI軟件具有自動掃描組件某種類型(如IDataGenerator)的實現,並與自己註冊的,當它的能力構造一個DataFactory的實例,它會自動包含它們。

+0

我正在使用NInject。僅僅在構造函數中有一個接口數組是不夠的,所以我可能必須先做一些綁定。現在要確定,有一些簡單的方法可以做到這一點,而無需進行擴展反射,這可以在沒有NInject的情況下直接完成。 – MilConDoin

+0

我一直在使用Ninject多年,一個數組將會正常工作。只需註冊您擁有的所有實例並注入即可。如果我正確地記得以下是支持的[],IEnumerable ,列表。請注意,當通過IEnumerable 注入時,它會在每個枚舉中進行延遲加載和重新評估,因此請注意這一點。 –

+0

是否有一種簡單且自動的方式來註冊實現從父類接口/派生的所有實例?我對NInject不太滿意。 – MilConDoin