This is the third post of the Design Pattern series and in this blog post, we will discuss “Abstract Factory Design Pattern” and its implementation in C# programming language. The Abstract Factory Pattern is used to instantiate an object and falls into the Creational Pattern category as defined by the Gang of Four (GoF). If you are new to design patterns, I would highly recommend you to read the introductory post “Introduction to Design Patterns“
What is an Abstract Factory Design Pattern
The Abstract Factory Pattern is a creational pattern that defines an interface for creating a family of related objects without specifying their implementation. To explain in simple words Abstract Factory Pattern is a design pattern that returns a factory class instance from a list of factories classes which in turn return the required concrete class instance.
The Abstract Factory Pattern is an extension over the Abstract Method Factory Pattern that represents a single family of instances whereas Abstract Factory represents multiple Factories of related objects.
Abstract Factory Pattern UML
A sample UML of the Abstract Factory Pattern implementation.
The major classes participating in the UML are as follows:
- DatabaseFactory: This is the Abstract Factory class that declares the interface to create an abstract product of NoSQLFactory and RelationDBFactory.
- NoSQLFactory and RelationDBFactory: These are the concrete factory implementation for creating the product for NoSQL and Relational databases respectively.
- MongoDB, CouchDB, SQLServerDB, and OracleDB: These are the classes that represent the products the factories will creating and returning the instance of.
- Client: The client class represents the service user.
Abstract Factory Pattern Use cases
- When you want to introduce loose coupling and reduce class dependencies for object creation.
- When you have families of related objects and you want to abstract the creation of this object for their service users.
Advantages of Abstract Factory
- Abstract Factory Pattern allows loose coupling.
- Allows object creation till runtime with the use of interface and an abstract class.
- New factories can be easily added without changing the client implementation.
- An existing factory can be modified without changing the client’s code.
Disadvantages of Abstract Factory
- Lots of interfaces and classes are introduced along with the pattern implementation this can introduce code complexity.
- The pattern is applicable to only families of related objects.
- Reduces code readability due to the level of abstraction it introduces.
Abstract Factory Design Pattern Implementation in C#
Let us realize the above given UML into a C# implementation. Here in the implementation, the Abstract Factory class creates an instance of NoSQLDB and RelationalDB factory instances which in turn returns the instance of MongoDB, CouchDB, and SQLServerDB, OracleDB instances respectively.
Interface INoSQLDB: This interface contains a single method GetConnection(), and the interface will be implemented by MongoDB and CouchDB concrete classes (products)
public interface INoSQLDB { string GetConnection(); } public class MongoDB : INoSQLDB { public string GetConnection() { return "This is MongoDB connection string"; } } public class CouchDB : INoSQLDB { public string GetConnection() { return "This is CouchDB connection string"; } }
Interface IRelationDB: This interface contains a single method GetConnection(), and the interface will be implemented by SQLServerDB and OracleDb concrete classes. Please note that INoSQLDB also exposes the same GetConnection() which can be further extracted to a single interface but for the sake of simplicity we are keeping in two different interfaces.
public interface IRelationDB { string GetConnection(); } public class SQLServerDB : IRelationDB { public string GetConnection() { return "This is SQLServerDB connection string"; } } public class OracleDB : IRelationDB { public string GetConnection() { return "This is OracleDb connection string"; } }
NoSQLDBFactory: This is the factory class that returns the object of the INoSQLDB type. This class exposes a single method Create(), that accepts the name of the database and returns the instance of it if the factory finds it valid.
public class NoSQLDBFactory { public INoSQLDB Create(string dbName) { if (dbName == "MongoDB") return new MongoDB(); else if (dbName == "CouchDB") return new CouchDB(); throw new ArgumentException("dbName is invalid"); } }
RelationDBFactory: This is the factory class that returns the object of IRelationalDB type. This class also exposes a single method Create(), that accepts the name of the database and returns the instance of it if the factory finds it valid.
public class RelationDBFactory { public IRelationDB Create(string dbName) { if (dbName == "SQLServerDB") return new SQLServerDB(); else if (dbName == "OracleDB") return new OracleDB(); throw new ArgumentException("dbName is invalid"); } }
IDBFactory: This is the interface that the Abstract Factory concrete class will implement and it contains two methods to returns the factory instances for INoSQLDB and IRelationDB.
public interface IDBFactory { INoSQLDB CreateNoSQLDB(string dbName); IRelationDB CreateRelationDB(string dbName); } public class DBFactory : IDBFactory { public INoSQLDB CreateNoSQLDB(string dbName) { NoSQLDBFactory factory = new NoSQLDBFactory(); return factory.Create(dbName); } public IRelationDB CreateRelationDB(string dbName) { RelationDBFactory factory = new RelationDBFactory(); return factory.Create(dbName); } }
Client: This is the client application that uses the DBFactory instance to get the desire database instance for its use.
class Client { static void Main(string[] args) { IDBFactory factory = new DBFactory(); //*** Getting a NOSQL database instance var noSQLDB = factory.CreateNoSQLDB("MongoDB"); Console.WriteLine(noSQLDB.GetConnection()); //** Getting a Relation database instance var relationDB = factory.CreateRelationDB("SQLServerDB"); Console.WriteLine(relationDB.GetConnection()); } }
Client Output:
This is MongoDB connection string This is SQLServerDB connection string
This concludes the post about the Abstract Factory Design Pattern and I hope you found this post helpful. Thanks for visiting, Cheers!!!
[Further Readings: Factory Method Pattern in C# | Singleton Design Pattern in C# | Introduction to Design Patterns | Microsoft C# Version History | Microsoft .NET Core Versions History | Microsoft .NET Framework Version History | Introduction to WPF in .NET Core | Useful Visual Studio 2019 extensions for database projects | Machine Learning Model Generation | Important Global Visual Studio 2019 Shortcuts | Datasets for Machine Learning | Top 7 Must-Have Visual Studio 2019 Extensions | AI vs ML vs DL – The basic differences | ASP.NET Core Blazor Server Application Project Structure | ASP.NET Core – Blazor Application an Introduction ]