Open In App

Factory method for designing pattern

Improve
Improve
Improve
Like Article
Like
Save Article
Save
Share
Report issue
Report

The factory method is a creational design pattern, i.e., related to object creation. The Factory Method pattern is used to create objects without specifying the exact class of object that will be created. This pattern is useful when you need to decouple the creation of an object from its implementation.

The idea is to create a factory class with a single responsibility to create objects, hiding the details of class modules from the user.
A factory pattern is one of the core design principles to create an object, allowing clients to create objects of a library(explained below) in a way such that it doesn’t have a tight coupling with the class hierarchy of the library.

What is meant when we talk about libraries and clients? 

A library is something that is provided by some third party that exposes some public APIs and clients make calls to those public APIs to complete their tasks. A very simple example can be different kinds of Views provided by Android OS. 

Implementation:

A. Without factory pattern

C++




// A design without factory pattern
#include <iostream>
using namespace std;
 
// Library classes
class Vehicle {
public:
    virtual void printVehicle() = 0;
};
class TwoWheeler : public Vehicle {
public:
    void printVehicle()
    {
        cout << "I am two wheeler" << endl;
    }
};
class FourWheeler : public Vehicle {
public:
    void printVehicle()
    {
        cout << "I am four wheeler" << endl;
    }
};
 
// Client (or user) class
class Client {
public:
    Client(int type)
    {
 
        // Client explicitly creates classes according to
        // type
        if (type == 1)
            pVehicle = new TwoWheeler();
        else if (type == 2)
            pVehicle = new FourWheeler();
        else
            pVehicle = NULL;
    }
 
    ~Client()
    {
        if (pVehicle) {
            delete pVehicle;
            pVehicle = NULL;
        }
    }
 
    Vehicle* getVehicle() { return pVehicle; }
 
private:
    Vehicle* pVehicle;
};
 
// Driver program
int main()
{
    Client* pClient = new Client(1);
    Vehicle* pVehicle = pClient->getVehicle();
    pVehicle->printVehicle();
    return 0;
}


Java




/*package whatever //do not write package name here */
 
import java.io.*;
 
// Library classes
abstract class Vehicle {
    public abstract void printVehicle();
}
 
class TwoWheeler extends Vehicle {
    public void printVehicle() {
        System.out.println("I am two wheeler");
    }
}
 
class FourWheeler extends Vehicle {
    public void printVehicle() {
        System.out.println("I am four wheeler");
    }
}
 
// Client (or user) class
class Client {
    private Vehicle pVehicle;
 
    public Client(int type) {
        if (type == 1) {
            pVehicle = new TwoWheeler();
        } else if (type == 2) {
            pVehicle = new FourWheeler();
        } else {
            pVehicle = null;
        }
    }
 
    public void cleanup() {
        if (pVehicle != null) {
            pVehicle = null;
        }
    }
 
    public Vehicle getVehicle() {
        return pVehicle;
    }
}
 
// Driver program
public class GFG {
    public static void main(String[] args) {
        Client pClient = new Client(1);
        Vehicle pVehicle = pClient.getVehicle();
        if (pVehicle != null) {
            pVehicle.printVehicle();
        }
        pClient.cleanup();
    }
}


Output

I am two wheeler


What are the problems with the above design? 

As you must have observed in the above example, the Client creates objects of either TwoWheeler or FourWheeler based on some input during the construction of its object. 

Say, the library introduces a new class ThreeWheeler to incorporate three-wheeler vehicles also. What would happen? The client will end up chaining a new else if in the conditional ladder to create objects of ThreeWheeler. Which in turn will need the Client to be recompiled. So, each time a new change is made on the library side, the Client would need to make some corresponding changes at its end and recompile the code. Sounds bad? This is a very bad practice of design.

How do we avoid the problem?

The answer is, to create a vehicle’s factory class with a single responsibility to create the objects.

B. With factory pattern

C++




// C++ program to demonstrate factory method design pattern
#include <iostream>
 
using namespace std;
 
enum VehicleType {
    VT_TwoWheeler,
    VT_ThreeWheeler,
    VT_FourWheeler
};
 
// Library classes
class Vehicle {
 
  public:
   
    virtual void printVehicleInfo() = 0;
    virtual ~Vehicle() {}
};
 
class TwoWheeler : public Vehicle {
public:
    void printVehicleInfo()
    {
        cout << "I am two wheeler" << endl;
    }
};
 
class ThreeWheeler : public Vehicle {
public:
    void printVehicleInfo()
    {
        cout << "I am three wheeler" << endl;
    }
};
 
class FourWheeler : public Vehicle {
public:
    void printVehicleInfo()
    {
        cout << "I am four wheeler" << endl;
    }
};
 
// Class Vehicle Factory with a single responsibility to
// construct Vehicles according to the clients requests. PS:
// This class can be extended to TwoWheelerFactory,
// ThreeWheelerFactory and so on.
class VehicleFactory {
public:
    Vehicle* build(VehicleType vehicleType)
    {
        if (vehicleType == VT_TwoWheeler)
            return new TwoWheeler();
        else if (vehicleType == VT_ThreeWheeler)
            return new ThreeWheeler();
        else if (vehicleType == VT_FourWheeler)
            return new FourWheeler();
        else
            return nullptr;
    }
};
 
// Client class. The client object will ask the factory to
// build vehicles.
class Client {
public:
    Client() { pVehicle = nullptr; }
 
    void BuildVehicle(VehicleType vehicleType)
    {
        VehicleFactory* vf = new VehicleFactory();
        pVehicle = vf->build(vehicleType);
 
        delete vf;
    }
 
    ~Client()
    {
        if (pVehicle) {
            delete pVehicle;
            pVehicle = NULL;
        }
    }
 
    Vehicle* getVehicle() { return pVehicle; }
 
private:
    Vehicle* pVehicle;
};
 
// Driver program
int main()
{
    Client* pClient = new Client();
 
    pClient->BuildVehicle(VT_TwoWheeler);
    pClient->getVehicle()->printVehicleInfo();
 
    pClient->BuildVehicle(VT_ThreeWheeler);
    pClient->getVehicle()->printVehicleInfo();
 
    pClient->BuildVehicle(VT_FourWheeler);
    pClient->getVehicle()->printVehicleInfo();
 
    delete pClient;
    return 0;
}


Java




// Java program to demonstrate factory method design pattern
 
enum VehicleType {
    VT_TwoWheeler,
    VT_ThreeWheeler,
    VT_FourWheeler
}
 
// Library Classes
abstract class Vehicle {
    abstract public void printVehicleInfo();
}
 
class TwoWheeler extends Vehicle {
    public void printVehicleInfo()
    {
        System.out.println("I am two wheeler");
    }
}
 
class ThreeWheeler extends Vehicle {
    public void printVehicleInfo()
    {
        System.out.println("I am three wheeler");
    }
}
 
class FourWheeler extends Vehicle {
    public void printVehicleInfo()
    {
        System.out.println("I am four wheeler");
    }
}
 
// Class Vehicle Factory with a single responsibility to
// construct Vehicles according to the clients requests.
// PS: This class can be extended to TwoWheelerFactory,
// ThreeWheelerFactory and so on.
 
// Class
class VehicleFactory {
 
    Vehicle build(VehicleType vehicleType)
    {
        if (VehicleType.VT_TwoWheeler.compareTo(vehicleType)
            == 0) {
            return new TwoWheeler();
        }
        else if (VehicleType.VT_ThreeWheeler.compareTo(
                     vehicleType)
                 == 0) {
            return new ThreeWheeler();
        }
        else if (VehicleType.VT_FourWheeler.compareTo(
                     vehicleType)
                 == 0) {
            return new FourWheeler();
        }
        return null;
    }
}
 
// Client class. The client object will ask the factory to
// build vehicles.
class Client {
 
    private Vehicle pVehicle;
 
    Client() { pVehicle = null; }
 
    void BuildVehicle(VehicleType vehicleType)
    {
        VehicleFactory vf = new VehicleFactory();
        pVehicle = vf.build(vehicleType);
    }
 
    Vehicle getVehicle() { return pVehicle; }
}
 
// Driver Program
public class GFG {
 
    // Main driver method
    public static void main(String[] args)
    {
        Client client = new Client();
        client.BuildVehicle(VehicleType.VT_TwoWheeler);
        client.getVehicle().printVehicleInfo();
 
        client.BuildVehicle(VehicleType.VT_ThreeWheeler);
        client.getVehicle().printVehicleInfo();
 
        client.BuildVehicle(VehicleType.VT_FourWheeler);
        client.getVehicle().printVehicleInfo();
    }
}


Output

I am two wheeler
I am three wheeler
I am four wheeler


In the above example, we have totally decoupled the selection of types for object creation from the Client. The factory class is now responsible for deciding which object type to create based on the input provided by the client. The client just needs to make calls to the factory class’ build method and pass the type it wants without worrying about the actual implementation of the creation of objects.

With this new implementation, the factory class can be extended as and when required. For example, if we start adding water transportation and need to add vehicles like ships, and submarines. New Library classes can be very easily added and extending the factory class won’t affect the client code at all.

Other examples of the Factory Method:

  1. Say, in a ‘Drawing’ system, depending on the user’s input, different pictures like squares, rectangles, the circle can be drawn. 
  2. Another example: On the travel site, we can book train tickets as well as bus tickets and flight tickets. In this case, the user can give his travel type as ‘bus’, ‘train’, or ‘flight’. 

In both the above examples, we can use the factory method design pattern to create instances depending on the user’s input. For adding a new type of shape, no need to change the client’s code.

Further, Read: Factory Method in Python



Like Article
Save Article
Previous
Next
Share your thoughts in the comments
Similar Reads