The best way to create a factory

I have read about the Factory pattern a lot lately. I am trying to find a better way to implement it. In the C # Agile Principles Templates Book and Practice, it is recommended that you create a Factory as follows:

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

Instead of...

 public class ShapeFactoryImplementation : ShapeFactory { public Shape MakeCircle() { return new Circle(); } public Shape MakeSquare() { return new Square(); } } 

Please tell me what you think? Or maybe there is a better way to implement a Factory pattern?

+6
source share
6 answers

The main theme of the factory template is to disconnect the client from creating objects.

In your second example, the client has a hard-coded form for creation, such as MakeCircle , and therefore tightly connects the creation of the object and the client.

+2
source

In the first version, the ShapeFactoryImplementation interface remains unchanged. In the second case, every time you add a new method, you have a new interface.

+3
source

In my opinion, both of these implementations violate at least a couple of rules, the principle of single responsibility (well, you could argue that he is responsible for creating, but IMO, that responsibility is too broad) and the Open / Closed principle (every time you add the form, you need to change the class). Not to mention that the first implementation does not allow you to provide parameters for constructors. The way that I usually 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 example, the creation settings are set using a static constructor, which still requires a class change; in a real scenario, I would add the AddSettings method for this or rely on the IoC container (if it provided such functionality).

By doing so, you have the advantage of loose coupling (you can change how objects are actually constructed during the separation process) and can add new types of shapes at any time convenient for you, without even having to rebuild the factory. In addition, you can provide designers with form-specific options for designers.

Of course, considering only this simple example of figure-building, this seems a little constructed, but I take this approach for more complex and realistic scenarios.

+3
source

If you think that using strings in the first method to select the shape you want is ugly, why not use enums?

+2
source

What you list here is called Simple Factory, the first is better, because the creation is mainly determined by the not method parameter.

In fact, the Factory method template is official, let's say there is IFoo, and there are two implementations of FooA, FooB as follows:

 public interface IFoo { } public class FooA : IFoo { } public class FooB : IFoo { } 

Then the problem arises when using IFoo in the client application - How to create an instance of the implementation? The connection exists because the client depends on creating FooA / FooB, even the FooC function, so we need a de-mutation. We transfer responsibility for instantiating the IFoo implementation 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 a FooB, we need:

 public class FooBFactory : IFooFactory { public IFoo CreateFoo() { return new FooB(); } } 

The effect here is when there is FooC, we donโ€™t need to modify the existing Factory, we just need to implement another FooCFactory.

+1
source

Personally, I like the first one. This allows you to easily expand the creation list. On the other hand, the second relies on various methods of creating new objects. If you add a method for the new form, it will break the ABI. You must change these protection methods so that new additions allow the public interface and derived classes to still change the way objects are created.

0
source

Source: https://habr.com/ru/post/896309/


All Articles