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

How to get number of concrete classes from factory pattern?

工厂模式通常为具体的 classes 创建一个基础 class,然后具体的 classes 从该基础 class 继承。对于很多应用程序,我们需要知道这个工厂可以创建的具体 classes 的数量。例如,一个创建典型 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. 在工厂中将数字设置为常量class并使其成为 public 可见。缺点是每次添加新的 形状,你要手动增加形状的数量。
  2. 创建一个包含所有实例的动态容器(C# 中的 List) 工厂可以创建的具体对象。优点是 它可以自动计算出它可以处理的形状数量 创建,即使添加了新的 Shape classes。缺点是 很明显,每种形状都必须与 要求形状!

最好的方法是什么?关于这个特定主题的最佳实践?

您可以将形状类型存储在数组中,然后使用 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);
    }
}

您可以创建一个为您存储常量的枚举。 这也有助于通过 IDE 的自动完成功能了解 'possibilities' 来帮助用户,此外它还可以防止用户输入数字 'out of bounds',例如在您的示例中输入“4”。 (请注意,我通常写 java... 所以 C# 不是我的强项,但你可以 'something' 类似于此)

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;
    }
}

每次添加新的可能性时都必须编辑 class 的 "issue" 是没有实际意义的,因为你每次这样做都必须编辑这个 class,现在你只需要编辑 'PossibleShapes' class。

(请注意,我仍然不认为这是工厂模式的正确用法,因为我不知道 'color' 和 'thickness' 值的来源,但至少这比使用反射更好)

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

此外,这允许用户自己轻松设置 color/thickness(仍然可以有默认值,但我没有将其放入此代码示例中)

表示由构建器创建的产品

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 否则没有办法解决这个问题。必须对某处的 builder/factory/etc 进行一些编辑。