Best way to build a factory
I have been reading about Factory pattern a lot lately. I am trying to figure out the best way to implement it. In the book C # Agile Principles patterns and practice the recommendation is to create the Factory like this:
public class ShapeFactoryImplementation : ShapeFactory {
public Shape Make(string name) {
if (name.Equals("Circle"))
return new Circle();
else if (name.Equals("Square"))
return new Square();
else
throw new Exception("ShapeFactory cannot create: {0}", name);
}
}
Rather than...
public class ShapeFactoryImplement开发者_开发百科ation : ShapeFactory {
public Shape MakeCircle() {
return new Circle();
}
public Shape MakeSquare() {
return new Square();
}
}
Please tell me what are your thoughts? Or maybe there is a better way to implement the factory pattern?
In the first version the interface of ShapeFactoryImplementation
remains the same. In the second every time you add a new method you have a new interface.
In my opinion both of these implementations break at least couple of rules, Single Responsibility Principle (ok, you could argue that it's responsible for creation, but IMO that's too broad responsibility) and Open/Closed Principle (every time you add a shape you need to change the class). Not to mention the fact, that the first implementation doesn't allow you to provide parameters for constructors. The way I tend to solve this is to use the following approach:
public struct ShapeCreationSettings
{
public Predicate<string> Predicate;
public Func<IShapeCreationParams, Shape> Creator;
}
public interface IShapeCreationParams
{}
public struct CircleCreationParams : IShapeCreationParams
{
public CircleCreationParams(int r) : this()
{
R = r;
}
public int R { get; private set; }
}
public struct SquareCreationParams : IShapeCreationParams
{
public SquareCreationParams(int a) : this()
{
A = a;
}
public int A { get; private set; }
}
public class ShapeFactory : IShapeFactory
{
protected static List<ShapeCreationSettings> settings = new List<ShapeCreationSettings>();
static ShapeFactory()
{
settings.Add(new ShapeCreationSettings
{
Predicate = t => t.Equals("Circle"),
Creator = p => new Circle(((CircleCreationParams) p).R)
});
settings.Add(new ShapeCreationSettings
{
Predicate = t => t.Equals("Square"),
Creator = p => new Square(((SquareCreationParams)p).A)
});
}
public Shape Create(string name, IShapeCreationParams p)
{
return settings.FirstOrDefault(s => s.Predicate(name)).Creator(p);
}
}
For the sake of the example, the creation settings are set using static constructor, which still requires the class to change, in real scenario I'd add a AddSettings method for this or rely on IoC container (if it'd provide such functionality).
By doing this you have the advantage of loose coupling (you can change how the objects are actually constructed in separation) and can add new types of shapes anytime you want without even rebuilding the factory. Plus you are able to provide shape-specific creation params to constructors.
Of course considering just this simple example of building shapes this seems over-engineered a little bit, but that's the approach I follow for more complex, real-life scenarios.
The main point of the factory pattern is to de-couple the client from the creation of objects.
In your second example, the client has hard-coded the shape to create, such as MakeCircle
, and therefore tightly couples the object creation and the client.
If you think the use of strings in the first method to select the desired shape is ugly, why not use enums?
What the two you list here are called Simple Factory, The first one is better, because creation is mainly decided by parameter not method.
Actually Factory Method Pattern is official, Let's say there is a IFoo, and there are two implementation FooA, FooB as follows:
public interface IFoo
{
}
public class FooA : IFoo
{
}
public class FooB : IFoo
{
}
Then there is a problem when use IFoo in client application - How to create an implementation instance? Coupling exist because client depend on the creation of FooA / FooB, even FooC in feature, so we need de-coupling. We move the creation responsibility of IFoo implementation instance to another interface :
public interface IFooFactory
{
IFoo CreateFoo();
}
to create FooA, we need:
public class FooAFactory : IFooFactory
{
public IFoo CreateFoo()
{
return new FooA();
}
}
to create FooB, we need:
public class FooBFactory : IFooFactory
{
public IFoo CreateFoo()
{
return new FooB();
}
}
The effect here is, when there is a FooC, we do not need to modify existing Factory, we just need to need implement another FooCFactory.
Personally I like the first. It allows you to easily expand the creation list. On the other hand the second relies on distinct methods to create new objects. If you add a method for a new shape it will break the ABI. You should change those methods to protected so new additions will keep the public interface and derived classes can still change how objects are constructed.
精彩评论