2016-04-22 71 views
1

我有一個用例,我需要建立一個工廠類,它返回基於傳遞的枚舉的不同具體類型。但是,每種類型都需要不同的構造函數參數。那麼,在這種情況下,擁有不同簽名的多種方法是否有意義,還是完全不是工廠模式?工廠方法模式可以使用不同的過載

我想這樣

class CarFactory 
{ 
    public ModelS TeslaMaker (List<Battery> batteries){/*return ModelS*/} 
    public Mustang FordMaker (Engine engine) {/*return a Mustang*/} 
} 

,而不是說

class CarFactory 
    { 
     public Car GetCar(CarType carType) //where CarType is an enum (Ford=0,Tesla=1) 
     { 
     switch(carType) 
     { case CarType.Ford: return new Mustang(); }//just an example 
     } 
    } 

編輯: 對我來說,我確實需要返回一個類家族。所以,如果它是特斯拉,返回一個ModelS,一個ModelSService,ModelSWarranty等等。因此,我將採用抽象工廠的方法,這將包裝這裏給出的建議。

+0

雖然第一個實際上並沒有枚舉部分。 – Nyerguds

+0

@Nyerguds - 是的,這就是爲什麼我懷疑它是否甚至是工廠模式。 – arviman

回答

0

是的,是工廠模式。 工廠模式表示創建Object的工廠,但讓子類決定實例化對象的方式。 這是真的在你的情況下,你的決定基於枚舉類型

2

沒有,這不是一個很好的例子因子模式。相反,如果您的Car類依賴於不同類型的組件,那麼您也可以爲這些工廠提供工廠。例如,用於汽車和引擎,你可以有這樣的:

public interface ICar 
    { 
     IEngine Engine { get; set; } 
    } 

    public class Mustang : ICar 
    { 
     private IEngine _engine = EngineFactory.GetEngine(EngineType.Mustang); 
     public IEngine Engine 
     { 
      get { return _engine; } 
      set { _engine = value; } 
     } 
    } 

    public class CarFactory 
    { 
     public ICar GetCar(CarType carType) 
     { 
      switch (carType) 
      { case CarType.Ford: return new Mustang(); } 
     } 
    } 

同樣的發動機

public interface IEngine { } 

    public class MustangEngine : IEngine 
    { 

    } 

    public class EngineFactory 
    { 

     public static IEngine GetEngine(EngineType engine) 
     { 
      switch (engine) 
      { case EngineType.Mustang: return new MustangEngine(); } 
     } 
    } 
+0

是的,因爲我有一系列要創建的對象,所以看起來我會在我的案例中使用抽象工廠。 – arviman

2

如果你需要創建對象的不同參數(電池特斯拉或引擎福特),你可以在不同的選擇解決方案: - 在創建工廠時傳遞所有這些參數 - 它將成爲具有此類可用細節的所有類型汽車的特定工廠;

class SpecificCarFactory 
{ 
    public SpecificCarFactory(IList<Battery> batteries, IList<Engine> engines) 
    { 
    //save batteries etc into local properties 
    } 
    public Car GetCar(CarType carType) 
    { 
    switch(carType) 
    { case CarType.Ford: return new Mustang(_engines.First()); } 
    } 
} 
  • 包封參數到類對象,並從工廠方法參數得到它們;

    class CarFactory 
    { 
         public Car GetCar(CarDetail carDetail) //where CarDetails     encapsulates all the possible car details 
         { 
          switch(carDetail.type) 
          { case CarType.Ford: return new Mustang(carDetail.Engine);//just an example 
          } 
         } 
    } 
    
+0

封裝很好,但由於每種類型都需要不同的參數,所以有一個步驟不應該忘記:檢查已定義到傳入對象中的參數(如果不是這只是'NullReferenceException'的奇蹟配方) – Sidewinder94

+0

當然應該通過使用斷言或CodeContracts框架來完成。 – VitaliyK

+0

我最初考慮過這個問題,但是當我只需要參數的一個子集時,我認爲這是一團亂七八糟的事情。 – arviman

4

所以,在這種情況下,它是有意義的具有不同特徵的多個方法,或者是不是一個工廠模式呢?

擁有具體方法的工廠沒有任何意義。如果您的客戶代碼必須決定使用哪種特定方法,爲什麼不直接調用特定車輛的構造函數?在你的例子中,工廠方法只是對特定構造函數的包裝。

另一方面,使用枚舉調用單個工廠方法可以讓客戶機動態決定創建哪個汽車,例如可以基於數據庫查詢做出決定。

有一些可能的方法圍繞您當前的方法。

一種選擇是擁有代表構造函數參數的類的層次結構。你甚至都不需要枚舉則由於參數類型,就足以推斷出其具體的汽車應創建:

public abstract class CarCreationParams { } 

public class FordCreationParams : CarCreationParams 
{ 
    public Engine engine; 
} 

... 

public class CarFactory 
{ 
    public Car GetCar(CarCreationParams parms) 
    { 
     if (parms is FordCreationParams) 
      return new Ford(((FordCreationParams)parms).engine); 
     ... 

另一種選擇是想你是否真的需要您福特與外部創建引擎(聚合),或者他們擁有引擎(組合)。在後一種情況下,您可以將無參數的構造函數暴露給您的特定車型:

public class Ford : Car 
{ 
    public Engine engine; 

    // car is composed of multiple parts, including the engine 
    public Ford() 
    { 
      this.engine = new FordEngine(); 
    } 

這使得工廠的實施變得更加容易。

+0

謝謝。這是一個很好的答案。像你說的那樣用構圖來實現它也可以起作用。但是,我正在考慮將Dependence Injection容器傳入工廠方法,並讓它連接DI容器而不是返回對象。這是因爲我需要連接一系列類而不只是一個對象。然而,這似乎違背了工廠關注原則的分離(爲什麼工廠關心DI容器)。所以我想我需要使用像「抽象工廠」這樣的東西。 – arviman

+1

閱讀我的教程,瞭解可能在內部使用DI容器的工廠,http://www.wiktorzychla.com/2016/01/di-factories-and-composition-root.html –

+0

實際上,您的教程在外部使用DI在客戶端。我也會這樣做,但是,我正在考慮將DI作爲參考參數傳遞到工廠的內部,因此工廠擴充了DI容器,而不是返回具體的類本身。 – arviman