Abstract Factory Pattern
Introduction:
Abstract factory pattern is a creational pattern that provides interface to produce family of related products without specifying their (product) concrete classes.
If an application is to be portable, it needs to encapsulate platform dependencies. i.e. operating system, DB.
Provide a level of indirection that abstracts the creation of families of related or dependent objects without directly specifying their concrete classes. The "factory" object has the responsibility for providing creation services for the entire platform family. Clients never create platform objects directly, they ask the factory to do that for them.
This mechanism makes exchanging product families easy because the specific class of the factory object appears only once in the application - where it is instantiated. The application can wholesale replace the entire family of products simply by instantiating a different concrete instance of the abstract factory.
UML diagram:
When to use,
- Use abstract factory when the code handles varies products of related families, and not create dependency (or) expose the concrete classes.
- when you have a class with a set of Factory Methods that blur its primary responsibility. In a well-designed program each class is responsible only for one thing. When a class deals with multiple product types, it may be worth extracting its factory methods into a stand-alone factory class or a full-blown Abstract Factory implementation.
How to use,
- Fist create an interface or abstract base class for each distinct product of the product family(button, checkbox), and make all the variant of the product follow the same interface.
- Second, create an abstract factory class - an interface with list of creation methods for all the products in the family group. For example, createbutton(), createCheckbox(). These methods should return the abstract product type which we defined in the first step.
- Third, we create separate factory class for each variant of the product (windows, mac) based on the abstract factory class.
- The client code has to work with both factories and products via their respective abstract interfaces. This lets you change the type of a factory that you pass to the client code, as well as the product variant that the client code receives, without breaking the actual client code.
- If the client is only exposed to the abstract interfaces, what creates the actual factory objects? Usually, the application creates a concrete factory object at the initialization stage. Just before that, the app must select the factory type depending on the configuration or the environment settings.
Implementation:
Sourcecode:https://github.com/krishnaKSA/design_patterns_cplusplus/blob/main/AbstractFactoryPattern/AbstractFactory.hpp
Create portable application which creates widgets like button, checkbox, etc., in windows, mac, linux, and other OS.
- Abstract Product A - Button
- Abstract Product B - Checkbox
- Concrete product A1 - WindowsButton
- Concrete product B1 - WindowsCheckbox
- Concrete product A2 - MacButton
- Concrete product B2 - MacCheckbox
- Abstract Factory - GUI Factory
- Concrete Factory 1 - WindowsFactory
- Concrete Factory 2 - MacFactory
Class Diagram:
Product Abstract Class:
//Abstract product class
class Button
{
public:
virtual void draw() =0;
};
class Checkbox
{
public:
virtual void draw() =0;
};
Concrete product Class:
//concrete product class
//windows button
class WindowsButton : public Button
{
public:
void draw() override
{
cout<<"Windows button created !!!"<<endl;
}
};
//Mac button
class MacButton : public Button
{
public:
void draw() override
{
cout<<"MAC button created !!!"<<endl;
}
};
//windows checkbox
class WindowsCheckbox : public Checkbox
{
public:
void draw() override
{
cout<<"Windows Checkbox created !!!"<<endl;
}
};
//Mac checkbox
class MacCheckbox : public Checkbox
{
public:
void draw() override
{
cout<<"MAC Checkbox created !!!"<<endl;
}
};
Abstract Factory Class:
//Abstract factory class
class GUIFactory
{
public:
virtual Button* createButton() =0;
virtual Checkbox* createCheckbox() =0;
};
Concrete Factory Class:
//Concrete factory class
//Windows
class WindowsFactory: public GUIFactory
{
public:
Button* createButton()
{
return new WindowsButton;
}
Checkbox* createCheckbox()
{
return new WindowsCheckbox;
}
};
//MAC
class MacFactory: public GUIFactory
{
public:
Button* createButton()
{
return new MacButton;
}
Checkbox* createCheckbox()
{
return new MacCheckbox;
}
};
Application :
//Application class
class Application
{
private:
GUIFactory* factory; //abstract factory class
//abstract product class
Button* button;
Checkbox* checkbox;
public:
//constructor
Application(GUIFactory* factory)
{
this->factory = factory;
this->button = this->factory->createButton();
this->checkbox = this->factory->createCheckbox();
}
void draw()
{
this->button->draw();
this->checkbox->draw();
}
};
Client code:
void testClientCode()
{
std::string config = "mac";
//windows widgets
GUIFactory* factory = nullptr;
if("windows" == config)
{
factory = new WindowsFactory;
}
else if("mac" == config)
{
factory = new MacFactory;
}
else{
//nullptr
}
if(nullptr != factory)
{
Application* appl = new Application(factory);
appl->draw();
}
}