Click here to Skip to main content
15,303,572 members
Articles / Programming Languages / C# 6.0
Article
Posted 12 Feb 2016

Stats

32.8K views
428 downloads
15 bookmarked

An idiots guide to Abstract Factory Pattern in C#

Rate me:
Please Sign up or sign in to vote.
3.44/5 (7 votes)
12 Feb 2016CPOL5 min read
This is how an idiot like me explains what is Abstract Factory pattern and how it could be used

Introduction

If you are a seasoned C#/Java application developer you should have used abstract factory pattern for sure. If you haven't...not to worry this idiot is here to help. When I started my coding days I did not realize the importance of this pattern initially, but thankfully my boss cum architect of the project was very particular about using certain design patterns in specific cases. So after bit of pushing myself I got the understanding and more importantly gained "where to use" sense regarding design patterns. 

Among all the design patterns this could be termed as most important rather frequent one. Before going forward I would assume that as a reader you know what an Abstract class is in OOPS. If you are not much familiar with that then please help yourself by goggling it out. 

Background

Design patterns come into rescue when try to solve some architectural problem in code. For example suppose in your application you have 3 different source of data - Webservices, Database and Excel import. Now when it comes to coding as a developer you need to take decision whether to write code separately for each data source or is there a way you could abstract the database type from the higher layer of the application, so that higher layer(Business logic/UI Layer) of the application doesn't need to worry whether the lower layers(Data layer) have changed or not. 

So the pattern we are going to use today is a specialized one to solve this kind of problem by isolating and abstracting different "types" of databases from rest of the application. 

Lets explore Using the code

So what does "Abstract Factory Pattern" do?

  1. It provides a generalized access point.
  2. It hides the details of the type, in our case database type from rest of the application. 

Lets try to elucidate the 2nd point : So in our example instead of working through 3 different classes of connection 1. SQLConnection 2. ExcelConnection 3. WebServiceConnection, we will only have one connection which will be visible to application layer i.e DataConnection class. 

 

Problem statement and theoretical resolution

So we have 2 database one is Sql Server other one is Ole Db. Now we want to use Abstract Factory pattern in a way that our application layer doesn't have to have separate implementations when connection changes. Everything will be abstracted in data layer itself.

 

To use this pattern there are 3 basic steps we have to follow -

  • Create an abstract class with the common properties/behavior.
  • Inherit the abstract classes into the other classes which has detail of the implementations.
  • Use factory pattern to get the Abstract type and perform concrete operations.

Step 1: Create an abstract class with the common properties/behavior.

At first lets create our Abstract class. So our AbstractDatabase abstract class has two properties

  1. Connection property (System.Data.Common.DBConnection)
  2. Command property (System.Data.Common.DBCommand)
C++
public abstract class AbstractDatabase
  {
        public virtual DbConnection Connection { get; set; }
        public virtual DbCommand Command { get; set; }
  }

Step 2: Inherit the abstract classes into the other classes which has detail  implementations.

Now as we know we cannot instantiate Abstract class. The instance classes would rather inherit it. 

So for our SQLServerDatabase class we will inherit from Database abstract class and Connection property will return SqlConnection and Command property will return SqlCommand. 

The code snippet below is doing nothing but instantiating connection and command for SQLConnection.

C++
public class SqlServerDatabase : AbstractDatabase
    {
        private DbConnection _connection = null;
        private DbCommand _command = null;

        public override DbConnection Connection
        {
            get
            {
                if(_connection == null)
                {
                    _connection = new SqlConnection(ConfigurationManager.ConnectionStrings["SqlServerConnection"].ConnectionString);
                }
                return _connection;
            }
            set
            {
                _connection = value;
            }
        }

        public override DbCommand Command
        {
            get
            {
                if(_command == null)
                {
                    _command = new SqlCommand();
                    _command.Connection = Connection;
                }
                return _command;
            }
            set
            {
               _command = value;
            }
        }

Now suppose as have an OleDB Connection datasource as well. For that we will create a new class OleDBDatabase. It will inherit and implement our abstract class. Here connection property will return OleDBConnection and command property will return OleDBCommand.

In the same way as described above the below code snippet is only instantiating connection and command for OleDbConnection.

C++
public class OleDbDatabase : AbstractDatabase
    {
        private DbConnection _connection = null;
        private DbCommand _command = null;

        public override DbConnection Connection
        {
            get
            {
                if(_connection == null)
                {
                    _connection = new OleDbConnection(ConfigurationManager.ConnectionStrings["OleDbServerConnection"].ConnectionString);
                }

                return _connection;
            }
            set
            {
                _connection = value;
            }
        }

        public override DbCommand Command
        {
            get
            {
                if (_command == null)
                {
                    _command = new OleDbCommand();
                    _command.Connection = Connection;
                }
                return _command;
            }
            set
            {
                _command = value;
            }
        }
    }

 

Step 3: Use factory pattern to get the Abstract type and perform concrete operations.

Here we come to last step to implement our pattern. So how does it help us to hide the details from rest of the application?

Answer to that question would be - rest of the application doesn't directly deal with the OleDBDatabase or SQLServerDatabase class. Rather it deals with the abstract class and in this process factory pattern would help us to find the right implementation. 

To demonstrate it I have created a small Forms Application which has two radio button. So the trick is whichever radio button you select it will only return that instance. 

 

C++
private void btnSelect_Click(object sender, EventArgs e)
        {
            AbstractDatabase database;

            if (radSqlServer.Checked)
            {
                database = new OleDbDatabase();
            }
            else
            {
                database = new SqlServerDatabase();
            }

            //Use Connection methods as you want it
        }

Lets discuss the above snippet : In the button click event we have selected the the database type. Type of database is abstract here. So when the higher layer of our application works with the database instance it need not know whether it is working with OleDb or SqlServer. It will simply work with the AbstractDatabase type. You need not to train your mind much to see what is happening over here. Instead of using concrete type we are simply using Abstract type to hide implementation details from other part of app.

N.B : I have uploaded a solution file for your reference. It has quite the same code that we have explored in this article. While using the solution file please add your proper connectionstrings to the app.config file. 

Real world application

So if you are developing an application which has 

1. Multiple data sources.

2. Multiple output file format - for example you have to output your report to PDF,excel,word etc. But you don't want your other part of the app know how you are doing.

3. Any scenario where you have multiple input/output type but you could generalize it to one. 

 

Advantage over concrete implementation

Let me give you a scenario in terms of our own example to understand the advantage of Abstract Factory Pattern. Suppose tomorrow a newer version of Oracle data source comes up and your mad client wants to use it in our application. What will you do then...will you rewrite the whole data layer application layer to accommodate the change? 

Your answer would be no if you have used Abstract Factory pattern. You will only create a new concrete class which inherits from the Abstract database type and based on the selection you need to instantiate the OracleDataClient and you are good to go.   

Happy coding guys. :) Will be more than happy to answer your questions 

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

SubhamoyBurman
Software Developer (Senior)
India India
.NET developer with close proximity to Mobile Technology(Xamarin/Windows Phone). Also passionate about ASP.NET MVC/WebApi development

Comments and Discussions

 
Suggestion[My vote of 2] Review abstract factory pattern Pin
Frank Sebastià15-Feb-16 19:35
MemberFrank Sebastià15-Feb-16 19:35 
GeneralRe: [My vote of 2] Review abstract factory pattern Pin
SubhamoyBurman15-Feb-16 23:52
professionalSubhamoyBurman15-Feb-16 23:52 
GeneralRe: [My vote of 2] Review abstract factory pattern Pin
Frank Sebastià16-Feb-16 0:21
MemberFrank Sebastià16-Feb-16 0:21 
GeneralRe: [My vote of 2] Review abstract factory pattern Pin
SubhamoyBurman16-Feb-16 0:36
professionalSubhamoyBurman16-Feb-16 0:36 
GeneralMy vote of 4 Pin
DotNetSteve13-Feb-16 3:46
MemberDotNetSteve13-Feb-16 3:46 
I would have also like to have seen something about interfaces as well (compare / contrast)
GeneralRe: My vote of 4 Pin
SubhamoyBurman13-Feb-16 3:50
professionalSubhamoyBurman13-Feb-16 3:50 
GeneralRe: My vote of 4 Pin
John Brett15-Feb-16 1:02
MemberJohn Brett15-Feb-16 1:02 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.