In my previous article Factory Method Design Pattern in C#, I had explained about Factory Method Design Pattern. In this article, I will explain Abstract Factory Design Pattern in C#.
Source Code: Complete source code can be downloaded from the following GitHub repo –
https://github.com/sudipta-chaudhari/AbstractFactoryDesignPattern_CSharp
This design pattern is also a Creational Design Pattern like the Factory Method Design Pattern.
Abstract Factory Pattern expands the Factory Method Design Pattern by unifying similar Factory Method classes under a unified abstract class. Thus, it can also be referred to as Factory of Factories. In a nutshell, Abstract Factory Pattern unifies related Factory Method Patterns as displayed in the high level UML diagram.
As the Factory Pattern was responsible for object creation without exposing instantiation logic to the client, the Abstract Factory Pattern is responsible for creating a set of dependent or related objects without exposing instantiation logic to the client.
Let us take the Factory Method Design Pattern code from our previous article to build the code for Abstract Factory Design Pattern.
In the previous article, I had created a ButtonFactory. In this article, I will create a TextBoxFactory and a UIFactory that houses both the ButtonFactory and TextBoxFactory.
Let’s begin by creating two UI controls – TextBox and RichTextBox. Create two concrete classes TextBox.cs and RichTextBox.cs with a Display() method as shown follows. Both these classes need to implement this interface IControl as shown follows.
1 2 3 4 5 6 7 8 9 10 11 12 | using System; namespace AbstractFactoryPattern { class TextBox : IControl { public void Display() { Console.WriteLine("TextBox displayed."); } } } |
1 2 3 4 5 6 7 8 9 10 11 12 | using System; namespace AbstractFactoryPattern { class RichTextBox : IControl { public void Display() { Console.WriteLine("RichTextBox displayed."); } } } |
Next create a TextBoxFactory.cs class as shown follows in the same way as ButtonFactory.cs class was created in the previous article Factory Method Design Pattern.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | namespace AbstractFactoryPattern { class TextBoxFactory { internal static IControl GetTextBox(int textBoxType) { IControl objTextBox; switch(textBoxType) { case 1: objTextBox = new TextBox(); break; case 2: objTextBox = new RichTextBox(); break; default: objTextBox = null; break; } return objTextBox; } } } |
Now create the AbstractFactory class UIFactory.cs as follows.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | namespace AbstractFactoryPattern { public abstract class UIFactory { internal static IControl GetUIElement(int uiElementType, int objectType) { IControl objUIElement; switch(uiElementType) { case 1: objUIElement = ButtonFactory.GetButton(objectType); break; case 2: objUIElement = TextBoxFactory.GetTextBox(objectType); break; default: objUIElement = null; break; } return objUIElement; } } } |
The method GetUIElement within this class accepts the first parameter which selects from the two factories – ButtonFactory and TextBoxFactory. The second parameter selects the corresponding concrete type from each factory Button or RadioButton and TextBox or RichTextBox and creates the corresponding object respectively.
Now, in the client which is Program.cs class having the Main() method, code is shown as follows:-
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | using System; namespace AbstractFactoryPattern { class Program { static void Main(string[] args) { Console.Write("Enter choice (1-2) for UI Element Type : "); Int16.TryParse(Console.ReadLine(), out short uiElementType); while (uiElementType != 1 && uiElementType != 2) { Console.Write("Please enter correct choice (1-2) for UI Element Type : "); Int16.TryParse(Console.ReadLine(), out uiElementType); } Console.Write("Enter choice (1-2) for Object Type : "); Int16.TryParse(Console.ReadLine(), out short objectType); while (objectType != 1 && objectType != 2) { Console.Write("Please enter correct (1 - 2) choice for UI Element Type : "); Int16.TryParse(Console.ReadLine(), out objectType); } IControl objUIElement = UIFactory.GetUIElement(uiElementType, objectType); Console.WriteLine(); objUIElement.Display(); Console.ReadKey(); } } } |
First the user is prompted to select the from the two factories – ButtonFactory and TextBoxFactory. Next the user is prompted to select the corresponding concrete type from each factory Button or RadioButton and TextBox or RichTextBox respectively.
Finally, the GetUIElement method from the Abstract Factory class named UIFactory is invoked by passing the two parameters mentioned above to get the Factory object. Client only refers to IControl type and Abstract Factory class UIFactory also gives the same type of reference. Client is completely detached from the concrete Factory classes. When new Factories are added like ScrollBarFactory with concrete classes like HorizontalScrollBar and VerticalScrollBar etc, we don’t need to recompile the client again.
Output of the above code looks as follows.
Class Diagram
UML diagram
This concludes the article – Abstract Factory Design Pattern in C#. I hope you liked this article. If you have any comments, questions or suggestions, please post them in the comments section below this article. I will try to respond at my earliest or somebody else reading the article and your comment will try to respond.