Search code examples
c#design-patternsfactory-pattern

How to get number of concrete classes from factory pattern?


Factory pattern usually creates a base class for the concrete classes and the concrete classes then inherit from that base class. For a lot of applications, we need to know the number of the concrete classes this factory can create. For instance, a factory that creates the typical Shape objects (circle, rectangular, etc.) C# code example below:

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

The user may want to know how many kinds of shapes are supported by the program. I know 2 ways to do this:

  1. Set the number as a constant in the factory class and make it visible to public. The drawback is that every time you add a new Shape, you have to manually increase the number of shapes.
  2. Create a dynamic container (List in C#) that contains all instances of the concrete objects the factory can create. The advantage is that it can automatically figure out the number of Shapes it can create, even if new Shape classes are added. The drawback is obvious, every kind of Shapes have to be created together with the Shape requested!

What is the best way to do this? Any best practice on this specific topic?


Solution

  • You can store the types of shapes in an array then use Activator to create the instance. This takes care of indexing, count, and simplifies your creation function.

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