Factory Method Design Pattern
Factory method design pattern deals with the problem of creating objects. In this pattern, there are subclasses which are responsible for deciding which class to instantiate.
I will explain a few terms, cited from http://www.dofactory.com/Patterns/PatternFactory.aspx, to conceive the structure easily before digging in the pattern.
Product : defines the interface of objects the factory method creates
Concrete Product : implements the Product interface
Creator : Declares the factory method, which returns an object of type Product. Creator may also define a default implementation of the factory method that returns a default Concrete Product object. It may also call the factory method to create a Product object
Concrete Creator : overrides the factory method to return an instance of a concrete product.
There are some reasons to choose factory method design pattern :
If developer doesn’t know which classes should be instantiated before execute business logic purpose.
If class constructor has complex statements.
You can apply dependency injection by using Factory Method pattern.
It helps to build Test Driven Design.
You can easily prevent to misuse “Concrete” classes.
To show an example of factory method design pattern I used Database product which was implemented by MSSQLconcrete product and Oracle concrete product. DatabaseFactory creator is responsible for returning an object of Database product. In addition, MSSQLDatabaseFactory and OracleDatabaseFactory override factory method. In this example Create() method, and return an instance of MSSQL or Oracle concrete product.
Lets look at the example below :
// product public abstract class Database { public abstract void OpenConnection(); } // concrete product internal class MSSQL : Database //line8 { private MSSQL() { } //line10 public static MSSQL Create() { return new MSSQL(); } public override void OpenConnection() { Console.WriteLine("MSSQL Database connection is ready"); } } // concrete product internal class Oracle : Database //line 20 { private Oracle() { } //line22 public static Oracle Create() { return new Oracle(); } public override void OpenConnection() { Console.WriteLine("Oracle Database connection is ready"); } } // creator public abstract class DatabaseFactory { public void Run() //line34 { Database database = Create(); database.OpenConnection(); } protected abstract Database Create(); } // concrete factory public class MSSQLDatabaseFactory : DatabaseFactory { protected override Database Create() //line46 { return MSSQL.Create(); } } // concrete factory public class OracleDatabaseFactory : DatabaseFactory { protected override Database Create() //line55 { return Oracle.Create(); } }
at line 8,20 : Classes are marked as internal to prevent using outside of same assembly. So that client is not able to use concrete product. It’s not required for Factory Method Pattern. But it’s worth to encapsulate and hinder improper use.
at line 10, 22 : Constructors have private access specify in order to not allow instantiate concrete products by using new keyword. Instead, there are public static method called Create() which returns concrete product.
at line 46,55 : Create() abstract method of DatabaseFactory is overridden and implement statements to return concrete product.
at line 34 : It has all business logic and perform business logic according to concrete product type. DatabaseFactory class doesn’t know anything about concrete product. So we can easily create an fake object to write unit tests without invoking concrete product. It gives us to apply test driven development and provide dependency injection.
As you see it’s also really easy to expand and add new concrete product for instance MySQL. You can implement MySQL database provider without modifying Creator (DatabaseFactory) and other Concrete Products (MSSQLDatabase or OracleDatabase). This solution reduces to make mistakes.
Using factory method design pattern :
static void Main(string[] args) { DatabaseFactory factory = new MSSQLDatabaseFactory(); //line3 factory.Run(); //line4 factory = new OracleDatabaseFactory(); //line6 factory.Run(); //line7 Console.ReadKey(); }
at line 3, 6 : factory object doesn’t have any information concrete products.
at line 4,7 : Run() method is invoked to perform database operations.
If you try to instantiate concrete product, MSSQL or Oracle, your project cannot be compiled. Because you don’t have access to concrete products which are marked as internal.
output is :
MSSQL Database connection is ready
Oracle Database connection is ready