In case a class instance shall be created, developers may give the advice to use a “factory”. This common term isn’t wrong but sometimes it’s better to define the exact type of factory you want to use. So, in this case, if you ask “Shall I use a Factory Method or an Abstract Factory” it can happen that you don’t get an answer because the differences or the patterns itself are not understand properly.
In previous articles I explained the Factory Method pattern and the Abstract Factory pattern. Please read these articles if you want to get information about the design patterns. Within this article I compare the two patterns and show their differences.
The following table shows a short summary of the most important differences between the Factory Method design pattern and the Abstract Factory design pattern.
Factory Method | Abstract Factory |
Implemented as single method | Implemented as object |
Factory is implemented within the object which shall be created | Factory is implemented in another object independent of the objects to create |
Create a single object | Creates a family if dependent objects |
Can be overridden in a subclass | Different abstract factories can be created |
Is used to hide the details about how the class instance is created | Is used to hide the details about which concreate classes are created |
The following example shows an implementation of both factory patterns. At first two type of classes are implemented: queries and commands. These classes will implement the Factory Method design pattern. Within the different query and command classes the factory method of the base class is used or an own one is implemented. Additional the Abstract Factory pattern is used to create families of objects. There are two factories creating the classes for a file based data store or a database based data store.
interface IQuery { string GetData(); } interface IQueryFactory { void CreateQuery(); } //------------------------------------------------- class Query : IQuery, IQueryFactory { public Query() { CreateQuery(); } public virtual void CreateQuery() { //implement object initialization logic here } public string GetData() { return "abc"; } } class FileQuery : Query { public override void CreateQuery() { //implement object initialization logic here } } class DatabaseQuery : Query { } class OracleDatabaseQuery : DatabaseQuery { public override void CreateQuery() { //implement object initialization logic here } } //------------------------------------------------- interface ICommand { void UpdateData(string data); } interface ICommandFactory { ICommand CreateCommand(); } //------------------------------------------------- class Command : ICommand, ICommandFactory { public virtual ICommand CreateCommand() { return new Command(); } public void UpdateData(string data) { // ... } } class DatabaseCommand : Command { } class FileCommand : Command { public override ICommand CreateCommand() { return new FileCommand(); } } //------------------------------------------------- interface IEnvironmentFactory { IQuery GetQuery(); ICommand GetCommand(); } class DatabaseBasedEnvironment : IEnvironmentFactory { public ICommand GetCommand() { return new DatabaseCommand(); } public IQuery GetQuery() { return new DatabaseQuery(); } } class FileBasedEnvironment : IEnvironmentFactory { public ICommand GetCommand() { return new FileCommand(); } public IQuery GetQuery() { return new FileQuery(); } }