In the previous article you might have read about Abstract Factory. It says
about abstracting a class with related objects. In this article we are
discussing the Factory Method pattern. I am using the same ADO.NET Provider
Factory class as the example.
Let us see the challenge and evolve to the solution.
Challenge
You are working on a windows application. The application has 2 types of users
based on the database license they have: SQL Server or Oracle.
So for each database operation you need to create the right database classes
based on an enumeration DatabaseType.
public
void InsertRecord()
{
if (AppContext.DatabaseType
== DatabaseType.SqlServer)
{
SqlConnection connection =
new SqlConnection();
SqlCommand command =
new SqlCommand();
command.Connection =
connection;
command.ExecuteNonQuery();
}
else if (AppContext.DatabaseType
== DatabaseType.Oracle)
{
OracleConnection connection =
new OracleConnection();
OracleCommand command =
new OracleCommand();
command.Connection =
connection;
command.ExecuteNonQuery();
}
}
The above code seems to be complex and needs repeating for each database
operation spread throughout the application.
How to stop the repeating code and make things better?
Definition
"Define an interface for creating an object, but let subclasses decide which
class to instantiate. Factory method lets a class defer instantiation to
subclasses."
Implementation
The above problem can be resolved using Factory Method pattern. Here we provide
an abstract class for defining the structure and associating all related objects
(using Abstract Factory). Then the sub classes will be created deriving from
this abstract class. The sub classes decide which classes to be instantiated.
The advantage is more quality and less code. Here we have to define an abstract
class named DbProviderFactory. (already ADO.NET contains it)
public
abstract class
DbProviderFactory
{
public
virtual DbCommand
CreateCommand();
public
virtual
DbCommandBuilder CreateCommandBuilder();
public
virtual DbConnection
CreateConnection();
public virtual
DbDataAdapter CreateDataAdapter();
public virtual
DbParameter CreateParameter();
}
Then from the above abstract class we can derive concrete classes.
public
class
SqlClientFactory :
DbProviderFactory
public override
DbConnection CreateConnection()
{
return new
SqlConnection();
}
public override
DbCommand CreateCommand()
{
return new
SqlCommand();
}
}
You can see from the above code SqlConnection() and SqlCommand() objects are
created and supplied for DbConnection and DbCommand types respctively. Here
DbConnection and DbCommand are other abstract classes.
Similarly the Oracle implementation follows:
public
class
OracleClientFactory : DbProviderFactory
{
public override
DbConnection CreateConnection()
{
return new
OracleConnection();
}
public override
DbCommand CreateCommand()
{
return new
OracleCommand();
}
}
Replacing the Original Code
Now we are ready to replace our Insert() method code with the Factory Method
classes. Here we are using an AppInit() code to create the factory which will be
used throughout the application.
public
void AppInit()
{
if (AppContext.DatabaseType
== DatabaseType.SqlServer)
AppContext.DbProviderFactory =
SqlClientFactory.Instance;
else if (AppContext.DatabaseType
== DatabaseType.Oracle)
AppContext.DbProviderFactory =
OracleClientFactory.Instance;
}
// NewInsertRecord method
private
void NewInsertRecord()
{
DbConnection connection =
AppContext.DbProviderFactory.CreateConnection();
DbCommand command =
AppContext.DbProviderFactory.CreateCommand();
command.Connection =
connection;
command.ExecuteNonQuery();
}
From the above code you can see that using Factory Method the code is reduced
considerably but at a cost of new classes. The pattern provides much flexibility
on adding a new database. (if another customer with PostgreSQL arrives)
Abstract and Concrete Derivation
The following image depicts the relation between the abstract and concrete
classes we have discussed.
Note
ADO.NET already includes the DbProviderFactory abstract class and concrete
classes like SqlClientFactory, OleDbFactory etc. Additionally, using an ORM like
Entity Framework automatically takes care of the database switching. The
scenario mentioned here is for learning purposes.
Summary
In this method we have seen the Factory Method pattern. The example we discussed
is included with the attachment.