如何从工厂模式中获取具体类的数量?

时间:2015-12-28 18:59:41

标签: c# design-patterns factory-pattern

工厂模式通常为具体类创建基类,然后具体类从该基类继承。对于很多应用程序,我们需要知道这个工厂可以创建的具体类的数量。例如,工厂创建典型的Shape对象(圆形,矩形等)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类,也要创建。缺点是 很明显,每种形状都必须与它一起创造 形状要求!
  3. 最好的方法是什么?关于这个特定主题的任何最佳实践?

3 个答案:

答案 0 :(得分:2)

您可以创建一个为您存储常量的枚举。 这也有助于通过了解“可能性”来帮助用户。通过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;
    }
}

"问题"每次添加新的可能性时都必须编辑课程是没有意义的,因为每次这样做时你都必须编辑这个课程,现在你只需要编辑“可能的形状”'也是一类。

(请注意,我仍然不认为这是正确使用工厂模式,因为我不清楚“颜色”和“厚度”值是什么来自,但至少这比使用反射更好)

答案 1 :(得分:1)

这是一个Builder Pattern示例,我认为这是一个更好的示例,为您封装对象创建。 (您可以使用工厂方法模式,而不是为要在构建器中获取的每个形状使用不同的命名方法)

另外,这允许用户轻松设置颜色/厚度(仍然可以有默认值,但我没有将其放入此代码示例中)

表示由构建器

创建的产品
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,但是没有办法解决这个问题。必须对某处的建筑商/工厂/等进行一些编辑。

答案 2 :(得分: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);
    }
}