Abstract Factory - Creational Design Pattern


Note: Last time while describing Abstract Factory Pattern, I made some mistakes in the design. Now I am revising the article again with different example, source code and text. Must read for those who read the previous article. I really apologize for design errors in the previous article.

Intent (Introduction):

Abstract Factory simplifies the creation of different families of related or dependent objects. It provides interfaces for this purpose and does not specify the concrete classes. It is like saying to start (create) a new family, you need to agree with the contract. 

Description:

There are in fact two main constructs in this pattern. One is Factory and the other is Product. Each Factory creates same set of products with its own implementation. The pattern only gives Abstract Factory, i.e., just describe which products must be made by any concrete factory and Abstract Products, i.e., which services a particular kind of product must provide. Put it simple, the pattern provides an interface (specification) for all the factories and for each product. In C# it can be easily implemented using interfaces. 

An Example:

An example is always the best if the picture of problem is not getting cleared. So, lets take an example. Suppose, in our Windowing System, we want to allow different vendors to provide Windowing Kits so as to make the GUI more versatile. To impose a certain standard for each Windowing Kit, we make use of Abstract Factory Pattern. We define an interface (WindowingKit), which says each concrete windowing kit, provided by any vendor, must have ability to create Window and Button (thus specifying Abstract Factory). But, we should also impose certain rules for creating button and window so as to make sure that different buttons and windows (products) from different Windowing Kit Providers (Concrete Factories) operate in the same way in spite of their different look and feel. This can be done by defining an interface for each of button and window so that each concrete window and button must have similar services with different implementations.

Class Diagram:  

Implementation:

First we define an interface named WindowingKit as

// Abstract Factory
interface WindowingKit
{
Window CreateWindow();
Button CreateButton();
}

This imposes that each Concrete Windowing Kit (class implementing this interface) will create Window and Button with the specified method (CreateWindow & CreateButton)and of specified type (Window & Button). Now, we should specify the types Window and Button. This is done by making the respective interfaces as

// Abstract Product1 - Window
interface Window
{
void Draw();
void Minimize();
string Title {get; set;}
}
// Abstract Product2 - Button
interface Button
{
void Draw();
bool Enabled { get; set; }
string Text { get; set; }
}

Here our specification for any Windowing Kit ends. Now each Windowing Kit Provider can make his/her own Windowing Kit by implementing these three interfaces in his/her own specific ways. Like one may provide Windowing Kit with rectangular buttons while other providing the kit with rounded buttons with images on face and etc. The most important part of this all is that our Windowing System will handle each kit in the same way using these interface reference as we will show soon.

Now, let we make a standard (or default) windowing kit. First we need to implement WindowingKit interface as

// Concrete Factory1 - Standard (Default) Kit
class StandardKit : WindowingKit
{
public Window CreateWindow()
{
return new StandardWindow();
}
public Button CreateButton()
{
return new StandardButton();
}
}

Note that CreateWindow() method of StandardKit is returning a new instance of StandardWindow which is its own defined class that implements the Window interface as

// Concrete Product1 Of Factory1
class StandardWindow : Window
{
private string title="MyStandard Window";
public void Draw()
{
Console.WriteLine("Drawing Standard Window: {0}...", title);
}
public void Minimize()
{
Console.WriteLine("Minimizing Standard Window: {0}...", title);
}
public string Title
{
get { return title; }
set
{
title = "MyStandard Window - " +
value;
Draw();
}
}
}

The same is true for CreateButton() Method of StandardKit. Also, in the similar way, another vendor has given her Windowing Kit implementation naming it ExternalKit. (See Source Code for this)

Finally in the Main method, our Windowing System uses each of the two Windowing Kits (StandardKit, ExternalKit) one by one to create and use their specific controls (products). The code for main method is like

static void Main(string[] args)
{
WindowingKit standard =
new StandardKit(); // creating StandardKit Factory
WindowingKit external = new ExternalKit(); // creating ExternalKit Factory
ArrayList winKits = new ArrayList(); // collecting the kits
winKits.Add(standard);
winKits.Add(external);
foreach(WindowingKit winKit in winKits) // using each kit
{
Window win = winKit.CreateWindow();
// Make a Window of this kit
win.Draw(); // Perform different operations
win.Minimize();
win.Title = "Notepad";
Console.WriteLine();
Button btn = winKit.CreateButton();
// Make a Button of this kit
btn.Draw(); // Perform different operations
btn.Text = "Submit";
Console.WriteLine();
}
}

The complete source code is also attached with the article. Take a look at it to understand it to full (Highly Recommended).

Benefits Achieved Through This Pattern:

By applying Abstract Factory Pattern in the given scenario here, the code is made highly reusable and extensible. The theme of object oriented programming is that the addition of new components (classes) should not impact the old components (or system) which is exactly what is happening. Different vendors may provide their own WindowingKit and the WindowingSystem can use each of these in exactly the same way. The Pattern imposes the restrictions as each of the WindowingKit is bound to be compatible with our Windowing System. Another advantage of Abstract Factory is that it provides room for creating families of related or dependent objects means our StandardButton will always be appearing on StandardWindow so it can make use of this (although, I personally wont encourage you to create such dependencies).


Similar Articles