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

本文关键字:获取 工厂 模式 | 更新日期: 2023-09-27 18:28:21

工厂模式通常为具体类创建一个基类,然后具体类从该基类继承。对于许多应用程序,我们需要知道这个工厂可以创建的具体类的数量。例如,一个创建典型形状对象(圆形、矩形等)的工厂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类。缺点是显然,每种形状都必须与请求形状

最好的方法是什么?在这个特定主题上有什么最佳实践吗?

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

您可以创建一个为您存储常量的枚举。这也有助于用户了解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"类。

(请注意,我仍然不认为这是工厂模式的正确使用,因为我不知道"颜色"answers"厚度"值来自哪里,但至少这比使用反射要好)

这里有一个构建器模式示例,我认为它为您封装对象创建提供了一个更好的示例。(你可以使用工厂方法模式,而不是为你想在构建器中"获得"的每个形状使用不同的命名方法)

此外,这允许用户自己轻松设置颜色/厚度(仍然可以有默认值,但我没有把它放在这个代码示例中)

表示生成器创建的产品

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,否则这是没有办法的。必须对某个建筑商/工厂等进行一些编辑。

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