Description
The factory design pattern belongs to the creational design patterns, it decouples the creation of the concrete object from the parent. In provides an interface that must be implemented by sub-classes and mandates the implementation of factory methods. These methods handle object initialization.
This technique will require a bit more work to implement, but the result will be a more flexible solution.
When?
The object needs to be extended to sub-classes. The base class is not aware of it’s sub-classes. The product implementation changes over time.
How?
It encapsulates object creation in one place. It doesn’t directly refer to concrete classes, it’s only aware of the interface they implement.
It may look like an over-stretch to apply this method to your project, especially is it’s a small size application. Without disregarding YAGNI (you may not need more classes over time, and this might look harder to achieve) there is a minimal consideration to be regarded for every application, a minimal code practice. This is recommended to keep a clean and readable code.
Imagine you have a list of forms in your application. You may want to extend them or reduce them over time. Factory pattern provides a clean solution to uncouple the base class from the forms by driving initialization away from the core.
Without Factory Pattern
Example : We have a car factory that creates Audi cars. We have 3 models defines.
//The Audi base class. All audi classes will inherit this class public abstract class AudiCar { public AudiModels CarType { get; } public AudiCar(AudiModels carType) { this.CarType = carType; } public override string ToString() { return CarType.ToString(); } } //Model Types public enum AudiModels { AudiEPhaeton, AudiA, AudiC } public class AudiModelA : AudiCar { public AudiModelA() : base(AudiModels.AudiA) { } } public class AudiModelC : AudiCar { public AudiModelC() : base(AudiModels.AudiC) { } } public class AudiModelEPhaeton : AudiCar { public AudiModelEPhaeton() : base(CarTypes.AudiModels.AudiEPhaeton) { } }
Now we have defined using classical OOP one base class that represents an Audi type and 3 models inheriting the base type. Now the Audi factory should new-up each type.
public class AudiFactory { public AudiCar Buy(AudiModels audiCarType) { switch(audiCarType) { //Imagine if you need to add another car. Then you need to add another line to this switch statement, //and to every switch statement simialr to this throughout the code case AudiModels.AudiA: return new AudiModelA(); case AudiModels.AudiC: return new AudiModelC(); case AudiModels.AudiEPhaeton: return new AudiModelEPhaeton(); default: return null; } } }
Factory Design Pattern
While the classical pattern works in many solutions, here I think it’s not the best practice. Factory pattern requires a little more work to be done but the outcome is a more flexible solution.
What changes? Not much really, we just have to create an interface that forces a Factory method. In most cases you would make your sub-classes to inherit this interface, in my example I created new classes for this.
//The base class doesn't change public abstract class AudiCar { public AudiModels CarType { get; } public AudiCar(AudiModels carType) { this.CarType = carType; } public override string ToString() { return CarType.ToString(); } } //The sub-class doesn't change (but this class usually inherits the interface) public class AudiA : AudiCar { public AudiA() : base(AudiModels.AudiA) { //this is the concrete Audi model } } //We introduces this interface that mandates a factory method public interface IAudiSpecs { //factory method - the factory will receive specs for the model and it will create the car AudiCar CreateCar(); } //This class has the factory method that initializes (in this case instantiates) the required object public class AudiASpecs : IAudiSpecs { //The factory needs to receive only the specs, this is now made extendable public AudiCar CreateCar() { return new AudiA(); } }
Now we need to create the factory which, as defined, is not aware of the concrete classes but it uses a factory method to create the object
public interface IAudiFactory { string Location { get; } //To all factories : This is your assignment AudiCar CreateCar(IAudiSpecs audiSpecs); } //A new york factory public class AudiNewYorkFactory : IAudiFactory { public string Location { get => "NewYork"; } public AudiCar CreateCar(IAudiSpecs audiSpecs) { //building car, hard labour return audiSpecs.CreateCar(); } } //A Singapore factory public class AudiSingaporeFactory : IAudiFactory { public string Location { get => "Singapore"; } public AudiCar CreateCar(IAudiSpecs audiSpecs) { //building car, hard labour return audiSpecs.CreateCar(); } }
Now we can instantiate a car using the following code:
AudiNewYorkFactory audiNewYorkFactory = new AudiNewYorkFactory(); AudiCar car = audiNewYorkFactory.CreateCar(new AudiASpecs());
Abstract Factory
The concept of an abstract factory is not far then that of a simple factory. It just abstracts away the factory and the model from the end user and provides means to define more then one factory.
The only downside of this method is that you have to create one class for each factory/model.
From my point of view this increases code quality because you are not hardcoding the instantiation of these types. Imagine an industry where changes are often, this method is not invasive, it just involves creating a new class.
public abstract class AudiAbstractBuilder { protected IAudiFactory AudiFactory; public AudiAbstractBuilder(IAudiFactory factory) { this.AudiFactory = factory; } public abstract AudiCar OrderCar(); } //A NY factory that creates only model E car public class AudiEPhaetonNYBuilder : AudiAbstractBuilder { public AudiEPhaetonNYBuilder() : base(new AudiNewYorkFactory()) { } public override AudiCar OrderCar() { IAudiSpecs specs = new AudiEPhaetonSpecs(); return this.AudiFactory.CreateCar(specs); } } //A singapore factory that creates Model E cars public class AudiEPhaetonSBuilder : AudiAbstractBuilder { public AudiEPhaetonSBuilder() : base(new AudiSingaporeFactory()) { } public override AudiCar OrderCar() { IAudiSpecs specs = new AudiEPhaetonSpecs(); return this.AudiFactory.CreateCar(specs); } }
Usage:
AudiAbstractBuilder audiEPhaetonNYProvider = new AudiEPhaetonNYBuilder(); AudiCar audiCar = audiEPhaetonNYProvider.OrderCar();