2014-10-07 88 views
0

我想提供某種類型的通用約束限制類的工廠,不過,我需要確保該產品創建具有一定的構造,以使我廠工作。通用工廠 - 預計某些構造

public interface IFactory<TProduct> 
    where TProduct: class, IMyRestriction 
{ 

    TProduct Create(); 

} 

類,它實現IMyRestriction:

public class MyRestriction : IMyRestriction { 

    public MyRestriction(IArgumentType1 arg1, IArgumentType2 arg2) { 
     ... 
    } 

} 

這將使這項工作...

public class MyFactory<TProduct> : IFactory<TProduct> 
    where TProduct: class, IMyRestriction 
{ 

    public TProduct Create() { 
     // args provided by factory constructor 
     Activator.CreateInstance(typeof(TProduct), arg1, arg2); 
    } 

} 

...但沒有像這樣的類:

public class MyDerivedRestriction : MyRestriction { 

    public MyDerivedRestriction() 
     : base(null, null) 
    { 

    } 

} 

我能夠限制的唯一方法在使用泛型的某個構造函數中使用new()約束,但在這種情況下沒有意義。

+0

您確定不應該使用IoC容器,例如['Autofac'](http://autofac.org/)或['StructureMap'](http:// docs .structuremap.net /)? – 2014-10-07 08:15:05

回答

2

你已經基本上回答了你自己的問題 - 如你所知,控制構造器的唯一約束類型是無參數的。

剩下的唯一選擇則是使用某種初始化方法代替構造函數,你通常會在構造函數中做的邏輯在Init方法

interface IMyRestriction 
{ 
    // use whichever arguments you wanted for construction 
    void Init(string myParam1, string myParam2) 
} 

public class MyFactory<TProduct> : IFactory<TProduct> 
    where TProduct: class, IMyRestriction, new() 
{ 

    public TProduct Create() { 
     TProduct p = new TProduct(); 
     p.Init(arg1,arg2); 
     return p; 
    } 

} 
0

在C#中,除了new()(無參數構造函數)之外,不能放置通用約束,該約束定義構造函數的所需簽名。

,你可以在這裏做的最好的是要麼依靠運行時異常,或重新編寫初始化邏輯使用的IMyRestriction而不是構造函數的參數屬性:

interface IMyRestriction 
{ 
    IArgumentType1 Property1 { get; set; } 
    IArgumentType2 Property2 { get; set; } 
} 

public class MyFactory<TProduct> : IFactory<TProduct> 
    where TProduct : class, IMyRestriction, new() 
{ 
    public TProduct Create() 
    { 
     var product = new TProduct(); 

     product.Property1 = arg1; 
     product.Property2 = arg2; 

     return product; 
    } 

} 
+0

我也考慮過屬性,但是當產品構造時需要提供參數,例如不允許以後通過屬性設置,因爲它們會混淆產品的邏輯。 – xvdiff 2014-10-07 08:02:21

+0

@xvdiff:您可能會考慮使用產品的延遲初始化。這實際上取決於實體的性質和業務邏輯。 – Dennis 2014-10-07 08:04:17

2

做,如果你需要創建不同類別的不同構造的簽名,你可能尋找一個Abstract Factory模式,其中每個實體類都有自己的執行該工廠接口:

#region Restriction Types 

public class MyRestriction : IMyRestriction { 
    public MyRestriction(IArgumentType1 arg1, IArgumentType2 arg2) { 
     ... 
    } 
} 

public class MyDerivedRestriction : MyRestriction { 
    public MyDerivedRestriction() 
     : base(null, null) 
    { 
    } 
} 

#endregion 

#region Factory interface 

public interface IFactory<TProduct> 
    where TProduct: class, IMyRestriction 
{ 
    TProduct Create(); 
} 

#endregion 

#region Factory implementations for each entity 

public class MyRestrictionFactory : IFactory<MyRestriction> 
{ 
    public MyRestriction Create() 
    { 
     // args provided by factory constructor 
     return new MyRestriction(arg1, arg2); 
    } 
} 

public class MyDerivedRestrictionFactory : IFactory<MyDerivedRestriction> 
{ 
    public MyDerivedRestriction Create() 
    { 
     return new MyDerivedRestriction(); 
    } 
} 

#endregion 

這似乎是創造更多代碼,但每個工廠類可以很小,而且它提供了更多的類型安全性並且更靈活,因爲工廠可以處理其實體的特性。

作爲這種模式的擴展,人們經常爲每個工廠添加接口,以便更好地在IOC容器中註冊並提供更多抽象,但您可能不需要這樣做。例如:

// this gets resolved in DI, so the IFactory<T> part is abstracted away 
public interface IMyRestrictionFactory 
{ 
    MyRestriction Create(); 
} 

public class MyRestrictionFactory : IFactory<MyRestriction>, IMyRestrictionFactory 
{ 
    public MyRestriction Create() 
    { 
     // args provided by factory constructor 
     return new MyRestriction(arg1, arg2); 
    } 
}