The abstract factory pattern is a software design pattern that provides a way to encapsulate a group of individual factories that have a common theme. It is one level of abstraction higher than the factory pattern. You can use this pattern when you want to return one of several related classes of objects, each of which can return several different objects on request. In other words, the Abstract Factory is a factory object that returns one of several factories.
One classic application of the abstract factory is the case where your system needs to support multiple “look-and-feel” user interfaces, such as Windows-9x, Motif or Macintosh. You tell the factory that you want your program to look like Windows and it returns a GUI factory which returns Windows-like objects. Then when you request specific objects such as buttons, check boxes and windows, the GUI factory returns Windows instances of these visual interface components.
In normal usage, the client software creates a concrete implementation of the abstract factory and then uses the generic interfaces to create the concrete objects that are part of the theme. The client does not know (or care) which concrete objects it gets from each of these internal factories since it uses only the generic interfaces of their products. This pattern separates the details of implementation of a set of objects from their general usage.
In software development, a factory is the location in the code at which objects are constructed. The intent in employing the pattern is to insulate the creation of objects from their usage. This allows for new derived types to be introduced with no change to the code that uses the base class.
Reason to use this design pattern. See the example below,
Intent:
Provide an interface for creating families of related or dependent objects without
Also Known As :
Kit
Motivation :
Consider a user interface toolkit that supports multiple look-and-feel standards, such as Motif and Presentation Manager. Different look-and-feels define different appearances and behaviors for user interface "widgets" like scroll bars, windows, and buttons. To be portable across look-and-feel standards, an application should not hard-code its widgets for a particular look and feel. Instantiating look-and-feel-specific classes of widgets throughout the application makes it hard to change the look and feel later.
We can solve this problem by defining an abstract WidgetFactory class that declares an interface for creating each basic kind of widget. There's also an abstract class for each kind of widget, and concrete subclasses implement widgets for specific look-and-feel standards. WidgetFactory's interface has an operation that returns a new widget object for each abstract widget class. Clients call these operations to obtain widget instances, but clients aren't aware of the concrete classes they're using. Thus clients stay independent of the prevailing look and feel.
There is a concrete subclass of WidgetFactory for each look-and-feel standard. Each subclass implements the operations to create the appropriate widget for the look and feel. For example, the CreateScrollBar operation on the MotifWidgetFactory instantiates and returns a Motif scroll bar, while the corresponding operation on the PMWidgetFactory returns a scroll bar for Presentation Manager. Clients create widgets solely through the WidgetFactory interface and have no knowledge of the classes that implement widgets for a
particular look and feel. In other words, clients only have to commit to an interface defined by an abstract class, not a particular concrete class.
particular look and feel. In other words, clients only have to commit to an interface defined by an abstract class, not a particular concrete class.
Applicability :
Use the Abstract Factory pattern when,
- a system should be independent of how its products are created, composed, and represented.
- a system should be configured with one of multiple families of products.
- a family of related product objects is designed to be used together, and you need to enforce this constraint.
- you want to provide a class library of products, and you want to reveal just their interfaces, not their implementations.
Structure 1:
structure 2:
Participants:
- AbstractFactory : declares an interface for operations to create abstract products
- ConcreteFactory : implements the operations to create products
- AbstractProduct : declares an interface for a type of product objects
- ConcreteProduct : defines a product object to be created by the corresponding concrete factory and also Implements the abstract product interface
- Client : uses only interfaces declared by AbstractFactory and AbstractProduct
Collaborations :
- Normally a single instance of a ConcreteFactory class is created at run-time This concrete factory creates product objects having a particular implementation. To create different product objects, clients should use a different concrete factory.
- AbstractFactory defers creation of product objects to its ConcreteFactory subclass.
Implementation:
Here are some useful techniques for implementing the Abstract Factory pattern.
- Factories as singletons.
- An application typically needs only one instance of a ConcreteFactory per product family. So it's usually best implemented as a Singleton.
- Creating the products.
- collection of Factory Methods : A common way to implement the creation of products is to define a factory method for each product in a concrete factory. It requires a new concrete factory subclass for each product family, even if the product families would differ only slightly.
- can be also implemented using Prototype : define a prototypical instance for each product in ConcreteFactory and This eliminates the need for a new concrete factory for each product family.
2. Defining Extensible Factories.
- AbstractFactory usually defines a different operation for each kind of product it can produce. Adding a new kind of product requires changing the AbstractFactory interface and all the classes that depend on it.
- A more flexible but less safe design is to add a parameter to operations that create objects. This parameter could be a class identifier, an integer, or anything else that specifies the kind of product to be created.
- Difficult to use in statically typed language, requires that all created objects have the same abstract base class, and the client is not able to access safely subclass specific operations as they will not be accessible through the abstract interface. This is a common trade-off for a highly flexible and extensible interface.
Benefits and Drawbacks
Abstract Factory helps to increase the overall flexibility of the application.Flexibility manifests itself both during runtime and design time.During design we donot have to predict all future uses of this application.Instead we create a generic framework,and develop implementations independently from the rest of the application.At runtime,application can easily integrate new features and resources.
A further benefit of this pattern is it simplifies testing the rest of the application.
We can define the AbstractFactory and AbstractProduct as an interface or an abstract class depending on the needs of the application and your preference.
Depending on how the factory is to be used,some variations of this pattern allow multiple ConcreteFactory objects to be produced,resulting in an application that can simultaneously use multiple families of ConcreteProducts.
Sample Code.
/************************************************************************** Program tested on RedHat Enterprise 5.4 x86_64 gcc 4.1.2
* Creational Patterns deal with initializing and configuring classes and objects
* Abstract Factory creates an instance of several families of classes
* We will take an example of Animal Classes and Abstract them.
* There are 2 types of animals; Herbivores and Carnivores.
* The rule of nature is that Carnivores eats Herbivores which will be shown
* Different animas live in different continents but the same rule applies
************************************************************************/
#include <iostream>
#include <string>
using namespace std;
//The CHerbivore class - The 'AbstractProductA' abstract class
class CHerbivore {
public:
virtual const string& getName(void)=0;
};
//Lets define couple of Herbivores called Cow and Deer
class CCow : public CHerbivore {//The 'ProductA1' class
public:
CCow() : m_strName("Cow"){};
const string& getName(void) {
return m_strName;
}
private:
string m_strName;
};
class CDeer : public CHerbivore {//The 'ProductA2' class
public:
CDeer() : m_strName("Deer"){};
const string& getName(void) {
return m_strName;
}
private:
string m_strName;
};
//The Carnivore class - The 'AbstractProductB' abstract class
class CCarnivore {
public:
virtual const string& getName(void)=0;
virtual void eat(CHerbivore& h) = 0;
};
//Lets define couple of Carnivores called Lion and Wolf
class CLion : public CCarnivore {//The 'ProductB1' class
public:
CLion(): m_strName("Lion"){};
const string& getName(void) {
return m_strName;
}
void eat(CHerbivore& h) {//override
cout << m_strName << " eats " << h.getName() << endl;
}
private:
string m_strName;
};
class CWolf : public CCarnivore {//The 'ProductB2' class
public:
CWolf() : m_strName("Wolf"){};
const string& getName(void) {return m_strName;}
void eat(CHerbivore& h) {//override
cout << m_strName << " eats " << h.getName() << endl;
}
private:
string m_strName;
};
//The 'AbstractFactory' abstract class
class CContinentFactory {
public:
virtual CHerbivore& CreateHerbivore() = 0;
virtual CCarnivore& CreateCarnivore() = 0;
};
class CAfricaFactory : public CContinentFactory {//The 'ConcreteFactory1' class
CHerbivore& CreateHerbivore() {
return *(dynamic_cast<CHerbivore *>(new CCow()));
}
CCarnivore& CreateCarnivore() {
return *(dynamic_cast<CCarnivore *>(new CLion()));
}
};
class CAmericaFactory : public CContinentFactory {//The 'ConcreteFactory2' class
CHerbivore& CreateHerbivore() {
return *(dynamic_cast<CHerbivore *>(new CDeer()));
}
CCarnivore& CreateCarnivore() {
return *(dynamic_cast<CCarnivore *>(new CWolf()));
}
};
//The 'Client' class
class CAnimalWorld {
public:
CAnimalWorld(CContinentFactory& factory):_herbivore(factory.CreateHerbivore()),_carnivore(factory.CreateCarnivore()) {
}
void RunFoodChain() {
_carnivore.eat(_herbivore);
}
private:
CHerbivore& _herbivore;
CCarnivore& _carnivore;
};
int main() {
//Create and run African Animal World
CContinentFactory& africa = *(dynamic_cast<CContinentFactory *>(new CAfricaFactory()));
CAnimalWorld& world1 = *(new CAnimalWorld(africa));
world1.RunFoodChain();
// Create and run the American animal world
CContinentFactory& america = *(dynamic_cast<CContinentFactory *>(new CAmericaFactory()));
CAnimalWorld& world2 = *(new CAnimalWorld(america));
world2.RunFoodChain();
return 0;
}
/*
* OUTPUT
*
[sgupta@rhel55x86 abstract-factory]$ c++ abstractFactory.cpp -o abstractFactory
abstractFactory.cpp:122:2: warning: no newline at end of file
[sgupta@rhel55x86 abstract-factory]$ ./abstractFactory
Lion eats Cow
Wolf eats Deer
[sgupta@rhel55x86 abstract-factory]$
*/
* Creational Patterns deal with initializing and configuring classes and objects
* Abstract Factory creates an instance of several families of classes
* We will take an example of Animal Classes and Abstract them.
* There are 2 types of animals; Herbivores and Carnivores.
* The rule of nature is that Carnivores eats Herbivores which will be shown
* Different animas live in different continents but the same rule applies
************************************************************************/
#include <iostream>
#include <string>
using namespace std;
//The CHerbivore class - The 'AbstractProductA' abstract class
class CHerbivore {
public:
virtual const string& getName(void)=0;
};
//Lets define couple of Herbivores called Cow and Deer
class CCow : public CHerbivore {//The 'ProductA1' class
public:
CCow() : m_strName("Cow"){};
const string& getName(void) {
return m_strName;
}
private:
string m_strName;
};
class CDeer : public CHerbivore {//The 'ProductA2' class
public:
CDeer() : m_strName("Deer"){};
const string& getName(void) {
return m_strName;
}
private:
string m_strName;
};
//The Carnivore class - The 'AbstractProductB' abstract class
class CCarnivore {
public:
virtual const string& getName(void)=0;
virtual void eat(CHerbivore& h) = 0;
};
//Lets define couple of Carnivores called Lion and Wolf
class CLion : public CCarnivore {//The 'ProductB1' class
public:
CLion(): m_strName("Lion"){};
const string& getName(void) {
return m_strName;
}
void eat(CHerbivore& h) {//override
cout << m_strName << " eats " << h.getName() << endl;
}
private:
string m_strName;
};
class CWolf : public CCarnivore {//The 'ProductB2' class
public:
CWolf() : m_strName("Wolf"){};
const string& getName(void) {return m_strName;}
void eat(CHerbivore& h) {//override
cout << m_strName << " eats " << h.getName() << endl;
}
private:
string m_strName;
};
//The 'AbstractFactory' abstract class
class CContinentFactory {
public:
virtual CHerbivore& CreateHerbivore() = 0;
virtual CCarnivore& CreateCarnivore() = 0;
};
class CAfricaFactory : public CContinentFactory {//The 'ConcreteFactory1' class
CHerbivore& CreateHerbivore() {
return *(dynamic_cast<CHerbivore *>(new CCow()));
}
CCarnivore& CreateCarnivore() {
return *(dynamic_cast<CCarnivore *>(new CLion()));
}
};
class CAmericaFactory : public CContinentFactory {//The 'ConcreteFactory2' class
CHerbivore& CreateHerbivore() {
return *(dynamic_cast<CHerbivore *>(new CDeer()));
}
CCarnivore& CreateCarnivore() {
return *(dynamic_cast<CCarnivore *>(new CWolf()));
}
};
//The 'Client' class
class CAnimalWorld {
public:
CAnimalWorld(CContinentFactory& factory):_herbivore(factory.CreateHerbivore()),_carnivore(factory.CreateCarnivore()) {
}
void RunFoodChain() {
_carnivore.eat(_herbivore);
}
private:
CHerbivore& _herbivore;
CCarnivore& _carnivore;
};
int main() {
//Create and run African Animal World
CContinentFactory& africa = *(dynamic_cast<CContinentFactory *>(new CAfricaFactory()));
CAnimalWorld& world1 = *(new CAnimalWorld(africa));
world1.RunFoodChain();
// Create and run the American animal world
CContinentFactory& america = *(dynamic_cast<CContinentFactory *>(new CAmericaFactory()));
CAnimalWorld& world2 = *(new CAnimalWorld(america));
world2.RunFoodChain();
return 0;
}
/*
* OUTPUT
*
[sgupta@rhel55x86 abstract-factory]$ c++ abstractFactory.cpp -o abstractFactory
abstractFactory.cpp:122:2: warning: no newline at end of file
[sgupta@rhel55x86 abstract-factory]$ ./abstractFactory
Lion eats Cow
Wolf eats Deer
[sgupta@rhel55x86 abstract-factory]$
*/
No comments:
Post a Comment