FACTORY METHOD
Introduction:
Factory method is a creational design pattern. This patterns helps to create the object of the class without specifying the exact class of the object that will be created. This is done by the Factory method either specified in the interface class and implemented by the base class or defined in the base class , and optionally overridden by the derived class rather than calling by the constructor.
Factory methods defines the interface to create the object , and let the subclass to decide which object to create.
when to use,
- To create object by the client but without specifying the exact concrete class details to client.
- To create object without directly calling constructor (new operator).
- When client should have access only to the interface class.
Github: source code link
Example,
Before factory class,
class IVehicle
{
public:
//pure virtual
virtual void printVehicleType() = 0;
};
//sub product class
class CSedan :public IVehicle
{
public:
//virtual method
void printVehicleType() override
{
cout << "Vehicle type is Sedan" << endl;
}
};
//sub product class
class CXUV :public IVehicle
{
public:
//virtual method
void printVehicleType() override
{
cout << "Vehicle type is XUV" << endl;
}
};
class CClient
{
IVehicle* vehicle;
public:
CClient() :vehicle(nullptr) {
}
//getVehicle
void getVehicle(eVehicleType type)
{
if (type == eSedan)
{
vehicle = new CSedan();
}
else if (type == eXUV)
{
vehicle = new CXUV();
}
else {
//return nullptr
}
}
void printVehicleDetails()
{
if (nullptr != vehicle)
{
vehicle->printVehicleType();
}
}
};
In the above program, Client is creating the vehicle object based on the vehicle type.
There are two issues here,
1. In future, If the more subclasses added for IVehicle, then client code also need to be changed.
If cases continues to grow in the client side.
2. Client is exposed to all the actual product classes information.
Client code should not get affected , If there are more classes added in the library side.
In the factory method, Client is only aware of the Interface class which has factoryMethod to create the instance of the class.
Client invokes the factoryMethod of the interface class to get the instance. In this way, if there is any changes in the subclasses of the product class, client will not get affected.
In this article, we are going to see three different types of Factory method implementation.
1. Factory method using abstract interface class
2. Factory method using concrete class
3. Factory method using object pool.
Factory method using abstract interface class:
Product subclasses or concrete product classes : CSedan , CXuv, CElectriccar.
Abstract Interface factory class: IVehicleFactory
Concrete factory class: CVehicleFactory
Factory Method,
//Sub creator class
class CVehicleFactory : public IVehicleFactory
{
public:
//Factory method to create instance
IVehicle* createProduct(eVehicleType type) override
{
IVehicle* vehicle = nullptr;
if (type == eSedan)
{
vehicle = new CSedan();
}
else if (type == eXUV)
{
vehicle = new CXUV();
}
else if (type == eElectricCar)
{
vehicle = new CElectricCar();
}
else {
//return nullptr
}
return vehicle;
}
};
Product object creation on client side,
void getVehicle(eVehicleType type)
{
vehicle = factory->createProduct(type);
}
Factory method using concrete class:
Product subclasses or concrete product classes : CSedan , CXuv, CElectriccar, CElectricBus.
Abstract Interface factory class: CVehicleFactory
Concrete factory class: CAllVehicleFactory
Factory method,
createProduct in CVehicleFactory class contains the object creation of the few products. Concrete class derived form CVehicleFactory class contains the object creation of the other products.
//Factory interface class - concrete class
class CVehicleFactory
{
public:
//Factory method to create instance
virtual IVehicle* createProduct(eVehicleType type)
{
IVehicle* vehicle = nullptr;
if (type == eSedan)
{
vehicle = new CSedan();
}
else if (type == eXUV)
{
vehicle = new CXUV();
}
else {
//return nullptr
}
return vehicle;
}
};
//Concrete class
class CAllVehicleFactory : public CVehicleFactory
{
public:
//Factory method to create instance
IVehicle* createProduct(eVehicleType type) override
{
IVehicle* vehicle = nullptr;
if (type == eSedan)
{
vehicle = new CSedan();
}
else if (type == eXUV)
{
vehicle = new CXUV();
}
else if (type == eElectricBus)
{
vehicle = new CElectricBus();
}
else if (type == eElectricCar)
{
vehicle = new CElectricCar();
}
else {
//return nullptr
}
return vehicle;
}
};
Product object creation on client side:
//getVehicle
void getVehicle(eVehicleType type)
{
vehicle = factory->createProduct(type);
}
Factory method using object pool:
Product subclasses or concrete product classes : CSedan , CXuv, CElectriccar, CElectricBus.
Abstract Interface factory class: IVehicleFactory
Concrete factory class: CVehicleFactory
Concrete factory class has the object pool. During the constructor call, this class creates instance of all the product class and store it in the pool. When createProduct function is invoked, this concrete factory class fetch the project object from the pool.
CVehicleFactory()
{
for (auto&& type : gAllVehicleTypes)
{
if (eVehicleType::eElectricBus == type)
{
objectPool[eVehicleType::eElectricBus] = new CElectricBus;
}
else if (eVehicleType::eElectricCar == type)
{
objectPool[eVehicleType::eElectricCar] = new CElectricCar;
}
else if (eVehicleType::eXUV == type)
{
objectPool[eVehicleType::eXUV] = new CXUV;
}
else if (eVehicleType::eSedan == type)
{
objectPool[eVehicleType::eSedan] = new CSedan;
}
else{ //something wrong
}
}
}
Factory method in the concrete factory class:
//Factory method to create instance
IVehicle* createProduct(eVehicleType type) override
{
IVehicle* vehicle = nullptr;
auto instance = objectPool.find(type);
if (instance != objectPool.end())
{
vehicle = instance->second;
}
return vehicle;
}
Product object creation on client side://getVehicle
void getVehicle(eVehicleType type)
{
vehicle = factory->createProduct(type);
}