2014-02-28 41 views
3

請考慮這一點。我想創建一個創建動物的工廠(模式,而不是創造一個新的起源)。我以爲我會聰明,創建具有3件事情,我需要這個工作類,使用仿製藥一勞永逸的工廠模式

  • 返回一個抽象的動物委託
  • 返回一個特定的動物,每動物製作方法
  • 使用委託

厭倦這樣了,並獲得每次我需要使用工廠模式時各創建方法的一個實例,我想我會比較聰明,一次解決它所有。所以,我創造了這個漂亮的類

class Factorable<T> where T: class, new() 
{ 
    delegate T CreateDelegate(); 
    static CreateDelegate DoCreate = new CreateDelegate (CreateSelf); 
    static T CreateSelf() 
    { 
     return new T(); 
    } 
} 

class Factory<T> where T : Factorable<T> 
{ 
    public Factorable<T>.CreateDelegate CreationMethod ; 
} 

我想,很酷,我可以做出一流的(動物)從該類繼承,所以我沒有寫和所有實例的所有具體的創建方法動物。所有這一切都要歸功於泛型。幾乎...看到這個:

class Animal:Factorable<Animal> {...} 
class Bird:Animal {...} 

Factory genesis = new Factory<Animal>(); 
genesis.CreationMethod = Animal.DoCreate; 
Animal instance = genesis.CreateAnimal(); //instance is a brand new abstract Animal 

genesis.CreationMethod = Bird.DoCreate; //lets make it create birds! 
instance = genesis.CreateAnimal(); // wrong, instance is still an abstract Animal 

有沒有什麼辦法可以解決這個問題?我希望Bird繼承的CreateSelf方法來創建鳥類,而不是抽象動物(不必爲Bird寫一個新的方法)。有沒有一種方法可以指定Animal從Factorable繼承,但是有它的後代用它自己的類型覆蓋泛型T?

東西(這是愚蠢的代碼,不工作)這樣

class Animal:Factorable<Animal... or better the actual type of the class that has inherited> 
+0

也許我失去了一些東西,但一個'Animal'如何從自身'可分解'通用繼承? – mclark1129

+1

@MikeC這在C#中是可行的。 – MarcinJuraszek

回答

3

難道你不過分了一點?假設Animal是你的基類:

public class Factory 
{ 
    public static T Create<T>() where T : Animal, new() 
    { 
     return new T(); 
    } 
} 

用法:對象調用工廠不知道確切的:

var a = Factory.Create<Animal>(); 
var b = Factory.Create<Bird>(); 

UPDATE

閱讀你的評論這是我的理解它後創建的實例的類型。它只知道它是動物或動物派生的類。那麼,這個怎麼樣:

public class Factory 
{ 
    private Type _outputType = typeof(Animal); 

    public void Produces<T>() where T : Animal, new() 
    { 
     _outputType = typeof(T); 
    } 

    public Animal CreateAnimal() 
    { 
     return (Animal)Activator.CreateInstance(_outputType); 
    } 
} 

注:使輸出型私人和使用Produces<T>設置它提供了簡單的方法,以確保輸出類型是動物或派生。

用法:

var f = new Factory(); // factory produces animals 
var a = f.CreateAnimal(); 
f.Produces<Bird>();  // from now on factory produces birds 
var b = f.CreateAnimal(); 
+0

工廠創建高級對象,允許其他需要它的類創建抽象類型。不過,它應該允許您將後代類類型注入已完成的層次結構中。這是我的代表的原因。假設我有一個圖書館來處理一個有Cage類的動物園。籠子使用工廠創造動物。 AnimalHandler類也是如此。整個庫完成並密封在一個DLL中。現在我想創建一個Aviary應用程序。理想情況下,有一種方法可以告訴工廠:好吧,不要創建動物,請僅創建鳥類(我的代理人)。 – cockypup

+0

更新了我的答案。請注意,變量'b'仍然是'Animal'類型,但是擁有'Bird'類的實例。這是你想要的嗎? –

+0

酷!這正是我所期待的。綠色複選標記爲你。 – cockypup

0

你不能做到這一點與靜態方法。試試這個:

class Factorable<T> where T: class, new() 
{ 
    delegate T CreateDelegate(); 
    CreateDelegate DoCreate = new CreateDelegate (CreateSelf); 
    T CreateSelf() 
    { 
     return new T(); 
    } 
} 
class Animal : Factorable<Animal>... 
... 
Factory genesis = new Factory(); 
genesis.CreateAnimal = (new Animal()).DoCreate; 
Animal instance = genesis.CreateAnimal(); 

genesis.CreateAnimal = (new Bird()).DoCreate; 
instance = genesis.CreateAnimal();