Factory & Abstract factory pattern
Amit Nadiger
Polyglot(Rust??, C++ 11,14,17,20, C, Kotlin, Java) Android TV, Cas, Blockchain, Polkadot, UTXO, Substrate, Wasm, Proxy-wasm,AndroidTV, Dvb, STB, Linux, Engineering management.
Factory Design Pattern
The Factory Design Pattern is a creational design pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created. This pattern is useful when there are many different types of objects that can be created, and the decision on which type to create should be made at runtime.
UML Dig:
? ? ? ? ? ? ? ? ? ? ? ? +-------------+
? ? ? ? ? ? ? ? ? ? ? ? |? Creator? ? |
? ? ? ? ? ? ? ? ? ? ? ? +-------------+
? ? ? ? ? ? ? ? ? ? ? ? | +factory()? |
? ? ? ? ? ? ? ? ? ? ? ? +-------------+
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
? ? ? ? ? +-------------------------------+
? ? ? ? ? |? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
?+-------------+? ? ? ? ? ? ? ? ? +-------------+
? |? ProductA? ?|? ? ? ? ? ? ? ? ? |? ProductB? ?|
? +-------------+? ? ? ? ? ? ? ? ? +-------------+
| +operation()|? ? ? ? ? ? ? ? ? | +operation()|
?+-------------+? ? ? ? ? ? ? ? ? +-------------+
In the above diagram, Creator is an abstract class or interface that defines a factory method factory() for creating objects. The concrete classes ProductA and ProductB are the specific objects that the factory can create, and each have their own operations.
The Factory pattern allows the Creator to create objects without having to know their specific class, instead relying on the concrete classes to provide their own implementation. This makes it easier to add or remove objects from the system without having to modify the Creator.
What problem does factory pattern solve:
The Factory Design Pattern mainly solves the problem of how to create objects without tightly coupling the client code to the concrete classes being created. By encapsulating object creation in a factory class, the client code can use polymorphism to create and work with objects of different types without having to know about the details of the creation process.
Let me list few more:
Below code is to create a car without the Factory pattern, you would need to create the objects directly in the client code. Here is an example of how to create a Honda and a Toyota car without using the Factory pattern:
#include<iostream>
#include <string>
// Product
class Car {
public:
virtual std::string getDescription() = 0;
};
// Concrete Products
class Honda : public Car {
public:
std::string getDescription() {
return "Honda Car";
}
};
class Toyota : public Car {
public:
std::string getDescription() {
return "Toyota Car";
}
};
int main() {
Car* car1 = new Honda();
std::cout << car1->getDescription() << std::endl;
Car* car2 = new Toyota();
std::cout << car2->getDescription() << std::endl;
delete car1;
delete car2;
return 0;
}
The main problem with the above code that does not use the Factory pattern is that it tightly couples the client code to the implementation details of the Car objects. In this example, the client code creates instances of the Honda and Toyota classes directly using the new operator.
This approach can become problematic if the implementation details of the Car classes change, or if new types of Car classes need to be added. If the client code is tightly coupled to the specific implementations of the Car classes, then any changes to the implementation details of those classes will require changes to the client code as well.
The Factory pattern helps to address this problem by encapsulating the object creation process in a separate class (the factory). This allows the client code to create Car objects without needing to know the specific implementation details of those objects. Instead, the client code simply calls a method on the factory to create the objects, and the factory is responsible for creating the objects and returning them to the client code.
By using the Factory pattern, you can decouple the client code from the object creation process, and make the code more maintainable and flexible.
Below code is using the factory design pattern for creating the car:
Example :
#include<stdio.h>
#include <string>
// Abstract Product
class Car {
public:
virtual std::string getDescription() = 0;
};
// Concrete Products
class Honda : public Car {
public:
std::string getDescription() {
return "Honda Car";
}
};
class Toyota : public Car {
public:
std::string getDescription() {
return "Toyota Car";
}
};
// Abstract Factory
class CarFactory {
public:
virtual Car* createCar() = 0;
};
// Concrete Factories
class HondaFactory : public CarFactory {
public:
Car* createCar() {
return new Honda();
}
};
class ToyotaFactory : public CarFactory {
public:
Car* createCar() {
return new Toyota();
}
};
int main() {
CarFactory* factory1 = new HondaFactory();
Car* car1 = factory1->createCar();
std::cout << car1->getDescription() << std::endl;
CarFactory* factory2 = new ToyotaFactory();
Car* car2 = factory2->createCar();
std::cout << car2->getDescription() << std::endl;
delete car1;
delete factory1;
delete car2;
delete factory2;
return 0;
}
In the example, we have an abstract Car class with two concrete implementations: Honda and Toyota. We also have an abstract CarFactory class with two concrete implementations: HondaFactory and ToyotaFactory. Each concrete factory is responsible for creating a concrete car object.
In the main function, we create two factories - one for Honda and one for Toyota - and use each to create a car object. We then print out the description of each car.
The advantage of using the Factory pattern is that it provides a way to encapsulate the creation of objects and delegate the responsibility of creating objects to sub-classes. This makes the code more flexible and easier to maintain, as changes to the implementation of the concrete classes can be made in the sub-classes without affecting the client code. In addition, this pattern can help to reduce code duplication and improve code organization.
The Factory design pattern is useful in situations where:
Examples of situations where the Factory pattern may be useful include:
Advantages
The Factory Design Pattern provides several advantages:
Limitations
The Factory Design Pattern has some limitations:
Abstract Factory pattern:
The Abstract Factory pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. It solves the problem of creating object instances without hardcoding the exact class types of those objects, making it easy to change the underlying implementation of those objects without affecting the code that uses them.
The Abstract Factory pattern is best suited for situations where you need to create families of related objects, but you don't want to hardcode those objects into your client code. This is especially useful when you need to swap out implementations of those objects without changing the client code.
UML Dig:
? ? ? ? ? ? ? ? ? ? ? ? ? ? +-------------
? ? ? ? ? ? ? ? ? ? ? ? ? ? |? ?Abstract? |
? ? ? ? ? ? ? ? ? ? ? ? ? ? |? ?Factory? ?|
? ? ? ? ? ? ? ? ? ? ? ? ? ? +-------------+
? ? ? ? ? ? ? ? ? ? ? ? ? ? | +createObjA()|
? ? ? ? ? ? ? ? ? ? ? ? ? ? | +createObjB()|
? ? ? ? ? ? ? ? ? ? ? ? ? ? +-------------+
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?^? ? ? ? ^
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|? ? ? ? |
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|? ? ? ? |
? ? ? ? ?+-------------------------------+? ? ?+-------------------------------+
? ? ? ? ?|? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|? ? ?|? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?|
?+-------------+? ? ? ?+-------------+ |? ? ?| +-------------+? ? ? ?+-------------+
?| Concrete? ? |? ? ? ?| Concrete? ? | |? ? ?| | Concrete? ? |? ? ? ?| Concrete? ? |
?| FactoryA? ? |? ? ? ?| FactoryB? ? |-|---->| FactoryA? ? |? ? ? ?| FactoryB? ? |
?+-------------+? ? ? ?+-------------+ |? ? ?+-------------+? ? ? ?+-------------+
?| +createObjA()|? ? ? ?| +createObjA()| |? ? ?| +createObjB()|? ? ? ?| +createObjB()|
?| +createObjB()|? ? ? ?| +createObjB()| |? ? ?| +createObjB()|? ? ? ?| +createObjB()|
?+-------------+? ? ? ?+-------------+? ? ? ?+-------------+? ? ? ?+-------------+
+
领英推荐
Here are some common situations where the Abstract Factory pattern is useful:
Let's look at an example to better understand the problem that the Abstract Factory pattern solves. Suppose we are developing a game that requires the creation of different types of characters such as wizards, knights, and archers. Each of these characters has a different set of attributes and abilities. If we were to create these characters directly in our code, we would need to hardcode the exact class types of these characters. This could make it difficult to modify the game in the future if we wanted to add new character types or modify the attributes of existing characters.
To solve this problem, we can use the Abstract Factory pattern. The Abstract Factory pattern provides an interface for creating families of related objects, such as the different types of characters in our game. Each family of objects is represented by a concrete factory, which implements the Abstract Factory interface. The client code can use the Abstract Factory to create objects without worrying about the details of how those objects are created.
Let's take a look at how we can implement the Abstract Factory pattern in C++ using the example of our game characters. We will define an Abstract Factory interface, a set of concrete factories that implement this interface for each type of character, and a set of abstract product classes that define the attributes and abilities of each type of character.
Without using the abstract factory pattern:
Suppose we start developing the game without using the Abstract Factory pattern. We could create the different types of characters directly in our code like this:
#include <iostream>
using namespace std;
class Wizard {
public:
? ? void printInfo() {
? ? ? ? cout << "This is a wizard character\n";
? ? }
};
class Knight {
public:
? ? void printInfo() {
? ? ? ? cout << "This is a knight character\n";
? ? }
};
class Archer {
public:
? ? void printInfo() {
? ? ? ? cout << "This is an archer character\n";
? ? }
};
int main() {
? ? Wizard* wizard = new Wizard();
? ? wizard->printInfo();
? ? Knight* knight = new Knight();
? ? knight->printInfo();
? ? Archer* archer = new Archer();
? ? archer->printInfo();
? ? return 0;
}
In the above example, we have created three classes, Wizard, Knight, and Archer, each of which represents a different type of character in our game. We create instances of these classes directly in our client code and call their methods to print information about each character.
While this approach works, it has a few limitations. For example, if we decide to add a new type of character, we need to modify our client code to create instances of this new class. If we have a lot of client code that depends on these classes, this could be a significant amount of work. Additionally, if we ever need to change the implementation of these classes, we need to modify every instance of these classes in our code.
To solve this problem, we can use the Abstract Factory pattern. Let's modify our code to use the Abstract Factory pattern instead:
After using the abstract factory pattern
#include <iostream>
using namespace std;
// Abstract Product
class Character {
public:
? ? virtual void printInfo() = 0;
};
// Concrete Product 1
class Wizard : public Character {
public:
? ? void printInfo() {
? ? ? ? cout << "This is a wizard character\n";
? ? }
};
// Concrete Product 2
class Knight : public Character {
public:
? ? void printInfo() {
? ? ? ? cout << "This is a knight character\n";
? ? }
};
// Concrete Product 3
class Archer : public Character {
public:
? ? void printInfo() {
? ? ? ? cout << "This is an archer character\n";
? ? }
};
// Abstract Factory
class CharacterFactory {
public:
? ? virtual Character* createCharacter() = 0;
};
// Concrete Factory 1
class WizardFactory : public CharacterFactory {
public:
? ? Character* createCharacter() {
? ? ? ? return new Wizard();
? ? }
};
// Concrete Factory 2
class KnightFactory : public CharacterFactory {
public:
? ? Character* createCharacter() {
? ? ? ? return new Knight();
? ? }
};
// Concrete Factory 3
class ArcherFactory : public CharacterFactory {
public:
? ? Character* createCharacter() {
? ? ? ? return new Archer();
? ? }
};
int main() {
? ? CharacterFactory* factory = new WizardFactory();
? ? Character* character = factory->createCharacter();
? ? character->printInfo();
? ? factory = new KnightFactory();
? ? character = factory->createCharacter();
? ? character->printInfo();
? ? factory = new ArcherFactory();
? ? character = factory->createCharacter();
? ? character->printInfo();
? ? return 0;
}
In the above example, we have created an abstract Product class, Character, which defines the interface for all characters in our game. We have also created concrete Product classes, Wizard, Knight, and Archer, which implement this interface for each type of character.
We have also created an abstract Factory class, CharacterFactory, which defines the interface for creating characters in
What is difference between Factory and Abstract Factory patterns?
Factory and Abstract Factory patterns share similarities, but they differ in a few keyways.
The Factory pattern provides a way to create objects without specifying the exact class of object that will be created. This allows the client code to be decoupled from the specific implementation details of the objects being created. The Factory pattern uses a single factory class to create objects.
On the other hand, the Abstract Factory pattern provides an interface for creating families of related objects without specifying their concrete classes. This allows the client code to be decoupled from the specific implementation details of the objects being created, while also providing a way to ensure that the objects being created are compatible with each other. The Abstract Factory pattern uses multiple factory classes to create objects, with each factory class responsible for creating a different set of related objects.
To better illustrate the differences between these two patterns, let's compare the code examples for the Factory pattern and the Abstract Factory pattern:
Factory pattern:
In the below example, we have a Product interface and two concrete Product classes, ConcreteProductA and ConcreteProductB. We also have a Factory interface and two concrete Factory classes, ConcreteFactoryA and ConcreteFactoryB. Each Factory class is responsible for creating a specific type of Product.
// Factory pattern example
#include <iostream>
using namespace std;
class Product {
public:
? ? virtual void info() = 0;
};
class ConcreteProductA : public Product {
public:
? ? void info() {
? ? ? ? cout << "This is a ConcreteProductA.\n";
? ? }
};
class ConcreteProductB : public Product {
public:
? ? void info() {
? ? ? ? cout << "This is a ConcreteProductB.\n";
? ? }
};
class Factory {
public:
? ? virtual Product* createProduct() = 0;
};
class ConcreteFactoryA : public Factory {
public:
? ? Product* createProduct() {
? ? ? ? return new ConcreteProductA();
? ? }
};
class ConcreteFactoryB : public Factory {
public:
? ? Product* createProduct() {
? ? ? ? return new ConcreteProductB();
? ? }
};
int main() {
? ? Factory* factory = new ConcreteFactoryA();
? ? Product* product = factory->createProduct();
? ? product->info();
? ? factory = new ConcreteFactoryB();
? ? product = factory->createProduct();
? ? product->info();
? ? return 0;
}
/*
amit@DESKTOP-9LTOFUP:~/OmPracticeC++$ ./a.out
This is a ConcreteProductA.
This is a ConcreteProductB.
*/
Abstract factory pattern:
// Abstract Factory pattern example
#include <iostream>
using namespace std;
class ProductA {
public:
? ? virtual void info() = 0;
};
class ConcreteProductA1 : public ProductA {
public:
? ? void info() {
? ? ? ? cout << "This is a ConcreteProductA1.\n";
? ? }
};
class ConcreteProductA2 : public ProductA {
public:
? ? void info() {
? ? ? ? cout << "This is a ConcreteProductA2.\n";
? ? }
};
class ProductB {
public:
? ? virtual void info() = 0;
};
class ConcreteProductB1 : public ProductB {
public:
? ? void info() {
? ? ? ? cout << "This is a ConcreteProductB1.\n";
? ? }
};
class ConcreteProductB2 : public ProductB {
public:
? ? void info() {
? ? ? ? cout << "This is a ConcreteProductB2.\n";
? ? }
};
class AbstractFactory {
public:
? ? virtual ProductA* createProductA() = 0;
? ? virtual ProductB* createProductB() = 0;
};
class ConcreteFactory1 : public AbstractFactory {
public:
? ? ProductA* createProductA() {
? ? ? ? return new ConcreteProductA1();
? ? }
? ? ProductB* createProductB() {
? ? ? ? return new ConcreteProductB1();
? ? }
};
class ConcreteFactory2 : public AbstractFactory {
public:
? ? ProductA* createProductA() {
return new ConcreteProductA2();
}
ProductB* createProductB() {
return new ConcreteProductB2();
}
};
int main() {
AbstractFactory* factory = new ConcreteFactory1();
ProductA* productA = factory->createProductA();
ProductB* productB = factory->createProductB();
productA->info();
productB->info();
factory = new ConcreteFactory2();
productA = factory->createProductA();
productB = factory->createProductB();
productA->info();
productB->info();
return 0;
}
/*
Op =>
amit@DESKTOP-9LTOFUP:~/OmPracticeC++$ ./a.out
This is a ConcreteProductA1.
This is a ConcreteProductB1.
This is a ConcreteProductA2.
This is a ConcreteProductB2.
*/
In this example, we have two sets of related Product classes, ProductA and ProductB. We also have two sets of concrete Product classes, ConcreteProductA1 and ConcreteProductA2 for ProductA, and ConcreteProductB1 and ConcreteProductB2 for ProductB. We also have an AbstractFactory interface and two concrete Factory classes, ConcreteFactory1 and ConcreteFactory2. Each Factory class is responsible for creating a set of related Products.
The key difference between the Factory pattern and the Abstract Factory pattern is that the Factory pattern only creates one type of object, while the Abstract Factory pattern creates multiple related objects. In the Factory pattern, the client code must choose the specific factory to use based on the type of object it needs. In the Abstract Factory pattern, the client code only needs to choose the specific factory based on the family of related objects it needs, and the factory will create all the related objects in that family.
In summary, while both the Factory pattern and the Abstract Factory pattern provide a way to decouple client code from the specific implementation details of objects being created, the Abstract Factory pattern provides an additional layer of abstraction by allowing the creation of related families of objects. This can be useful in situations where multiple related objects need to be created together, or where the specific implementation details of the objects being created may change over time.
Here are some common scenarios where you might want to use either the Factory pattern or the Abstract Factory pattern:
Factory Pattern:
Abstract Factory Pattern:
Overall, the Factory pattern is useful when you only need to create one type of object, while the Abstract Factory pattern is useful when you need to create families of related objects.
Thanks for reading. Please comment if you have any questions or suggestions.
Architect | Designer | Java Developer | AWS Cloud Engineer Project Management Certification- IIT Delhi & B. Tech from UP Technical University
1 个月Hi - In your Factory Design Pattern code you are still instantiating the HondaFactory and ToyotaFactory in client code so if new car is introduced then you may have to change the client code, which is wrong? How come you achieved the encapulation?