2015-12-28 21 views
-1

工廠模式通常爲具體類創建基類,然後從該基類繼承具體類。對於很多應用程序,我們需要知道這個工廠可以創建的具體類的數量。例如,工廠,創建典型形狀的對象(圓的,矩形的等),C#代碼下面的例子:如何從工廠模式中獲取具體類的數量?

public class ShapeFactory 
{ 
    public IShape GetShape(int shapeIndex) 
    { 
     IShape s = null; 
     const int color = 1; 
     const int thickness = 5; 

     switch (shapeIndex) 
     { 
     case 1: s = new Square(color, thickness); 
      break; 
     case 2: s = new Triangle(thickness); 
      break; 
     case 3: s = new Circle(color); 
      break; 
     } 

     return s; 
    } 
} 

用戶可能想要知道有多少種形狀的由程序的支持。我知道有兩種方法可以做到這一點:

  1. 將數字設置爲工廠類中的一個常量,並使其對公衆可見 。缺點是每次添加新的圖形時,都必須手動增加圖形的數量。
  2. 創建一個動態容器(C#中的List),其中包含工廠可以創建的具體對象的所有實例 。優點是 ,即使添加了新的Shape類,它也可以自動計算出它可以創建的形狀數量 。缺點是 顯而易見,每種形狀都必須與 一起創建形狀請求!

這樣做的最好方法是什麼?關於這個特定主題的任何最佳實踐?

+0

這種工廠的預期公共接口是什麼?你能顯示一些代碼嗎? –

+0

你能舉一個例子,你什麼時候需要知道工廠可以創建的具體類的數量? – adv12

+0

@YacoubMassad,請參閱編輯。 – james

回答

0

您可以將形狀類型存儲在數組中,然後使用Activator創建實例。這會照顧索引,計數並簡化您的創建功能。

static class ShapeFactory 
{ 
    private static readonly Type[] _shapes = new Type[] { typeof(Square), typeof(Triangle), typeof(Circle) }; 

    public static int FactorySize 
    { 
     get 
     { 
      return _shapes.Length; 
     } 
    } 

    public static IShape GetShape(int shapeIndex, params object[] ctorParams) 
    { 
     return (IShape)Activator.CreateInstance(_shapes[shapeIndex], ctorParams); 
    } 
} 
+0

謝謝你,@Marco。這是一個很好的解決方案,但是如何處理帶有各種參數的構造函數呢?例如,Square的ctor採用(int color),Triangle的ctor採用(int color,int thickness)等。 – james

+0

@james see edit。只需添加一個對象[]參數即可。有關信息,請參閱文檔:https://msdn.microsoft.com/en-us/library/wcxyzt4d.aspx –

+0

感謝您使用此解決方法。我會接受你的回答。然而,這個解決方案將構造細節暴露給調用者(例如不同形狀的構造函數參數),這可能不是一個好設計。如果您將代碼與原始代碼進行比較,您可以看到原始代碼只需要一個參數shapeIndex。其他構造函數的參數可以**作爲GetShape函數中的常量。如果您能爲此提供建議,我將不勝感激。 – james

2

你可以創建一個爲你存儲常量的Enum。 這也有助於用戶通過IDE的自動完成功能瞭解「可能性」,並且可以防止用戶輸入數字「越界」,例如在示例中輸入「4」。 (請注意,我一般寫java ...所以C#是不是我的專長,但你可以做「東西」與此類似),其每次添加時間編輯類

public class ShapeFactory 
{ 
    enum PossibleShapes {CIRCLE, 
        SQUARE, 
        TRIANGLE, // c# allows you to do this (extra comma) on constructors, not sure about Enums, and helps with reducing 'bad' line changes in git/etc. 
        }; 
    public IShape GetShape(PossibleShapes whichShape) 
    { 
     IShape s = null; 

     switch (shapeCode) 
     { 
     case PossibleShapes.SQUARE : s = new Square(color, thickness); 
      break; 
     case PossibleShapes.TRIANGLE: s = new Triangle(thickness); 
      break; 
     case PossibleShapes.CIRCLE: s = new Circle(color); 
      break; 
     } 

     return s; 
    } 
} 

的「問題」一種新的可能性是沒有意義的,因爲每次你做這個時你都必須編輯這個類,現在你只需要編輯'PossibleShapes'類。 (請注意,我仍然不認爲這是工廠模式的正確用法,因爲我不知道「顏色」和「厚度」值來自哪裏,但至少這比使用反射)

+0

謝謝,@mawalker。但是這並不告訴調用者**可以創建多少個具體的類,這是我首先提出的問題...... – james

+0

您能否詳細說明爲什麼這比使用反射更好? – james

+0

然後只需創建一個靜態的#,因爲這就是你需要做的,或者是一個返回#的方法。但是,我沒有看到 - 爲什麼您需要將此信息提供給最終用戶。這是更好的原因是因爲1)它隱藏了構造函數的詳細信息,2)反射代價很高3)這種模式中的代碼少於添加所有參數檢查邏輯以確保參數有效的代碼4)可能更多的是我想不起我的頭頂,但安全性和可預測性浮現在腦海。 – mawalker

1

這裏是一個Builder Pattern例子,我認爲是一個更好的例子封裝你的對象創建。(您可以使用工廠方法模式,而不是在構建器中爲每個Shape創建不同的命名方法)

此外,它允許用戶輕鬆設置顏色/厚度(仍然可以有默認值,但我並沒有將它放入此代碼示例)

表示由製造商

public class Shape 
{ 
    public Shape() 
    { 
    } 

    public int Color { get; set; } 

    public int Thickness { get; set; } 
} 

建設者抽象出的產品

public interface IShapeBuilder 
{ 
    // Adding NotNull attribute to prevent null input argument 
    void SetColor([NotNull]string colour); 

    // Adding NotNull attribute to prevent null input argument 
    void SetThickness([NotNull]int count); 

    Shape GetShape(); 
} 

具體實施建設者

public class ShapeBuilder : IShapeBuilder 
{ 
    private Shape _shape; 

    public ShapeBuilder() 
    { 
    } 

    public int GetNumberShapesPossible() 
    { 
     //return some # here 
    } 

    public void GetSquare(){ 
     this._shape = new Square(); 
    } 

    public void GetCircle(){ 
     this._shape = new Circle(); 
    } 

    public void SetColor(string color) 
    { 
     this._shape.Color = color; 
    } 

    public void SetThickness(int thickness) 
    { 
     this._shape.Thickness = thickness; 
    } 

    public Shape Build() 
    { 
     return this._shape; 
    } 
} 

導演

public class ShapeBuildDirector 
{ 
    public Shape Construct() 
    { 
     ShapeBuilder builder = new ShapeBuilder(); 

     builder.GetCircle(); 

     builder.SetColour(2); 
     builder.SetThickness(4); 

     return builder.GetResult(); 
    } 
} 

你將必須從某個地方改變一些代碼,當你想新的具體類添加到庫中。除非你打算把具體的課程打包成某種.dll,否則就沒有辦法。必須對建築者/工廠等進行一些編輯。