The factory pattern

 The factory pattern

As discussed in the previous chapter, inheritance is one of the fundamental concepts in object-oriented programming. Along with subtyping polymorphism, it gives us the is/a relationship. A Car object can be handled as a Vehicle object. A Truck object can be handled as a Vehicle object too. On one hand, this kind of abstraction makes our code thinner, because the same piece of code can handle operations for both Car and Truck objects. On the other hand, it gives us the option to extend our code to new types of Vehicle objects by simply adding new classes such as Bike and Vanwithout modifying it.

When we deal with such scenarios, one of the trickiest parts is the creation of objects. In object-oriented programming, each object is instantiated using the constructor of the specific class, as shown in the following code:

Vehicle vehicle = new Car();

This piece of code implies a dependency between the class which instantiates an object and the class of the instantiated object. Such dependencies make our code tightly coupled and harder to extend without modifying it. For example, if we need to replace Car with another type, let's say Truck, we need to change the code accordingly:

Vehicle vehicle = new Truck();

But there are two problems here. First of all, our class should be open for extension but closed for modification (the open/closed principle). Second of all, each class should have only one reason to change (the single responsibility principle). Changing the main code each time we add a new class will break the open/closed principle, and having the main class responsible for instantiating vehicle objects in addition to its functionality will break the single responsibility principle.

In this case, we need to come up with a better design for our code. We can add a new class that is responsible for instantiating vehicle objects. We are going to call the pattern based on this SimpleFactory class.


Simple factory pattern

The factory pattern is used to encapsulate the logic to instantiate objects referred through a common interface. New classes can be added with minimal changes.

The implementation of a simple factory is described in the following class diagram:


The SimpleFactory class implements the code to instantiate ConcreteProduct1 and ConcreteProduct2. When the client needs an object, it calls the createProduct() method of the SimpleFactory with the parameter indicating the type of object it requires. SimpleFactory instantiates the corresponding concrete product and returns it. The returned product is cast to the base class type so the client will handle any Product in the same way, regardless of whether it is a ConcreteProduct1 or ConcreteProduct2.

Let's write a simple factory to create instances of vehicles. We have an abstract Vehicle class and three concrete classes inherited from it: BikeCar, and Truck. The factory, also called the static factory, will look like this:

public class VehicleFactory 
{
public enum VehicleType
{
Bike,Car,Truck
}
public static Vehicle create(VehicleType type)
{
if (type.equals(VehicleType.Bike))
return new Bike();
if (type.equals(VehicleType.Car))
return new Car();
if (type.equals(VehicleType.Truck))
return new Truck();
else return null;
}
}



The factory looks very simple and is responsible for the instantiation of the vehicleclasses, complying with the single responsibility principle. It helps us to reduce coupling because the client depends only on the Vehicle interface, complying with the dependency inversion principle. If we need to add a new vehicle class, we need to change the VehicleFactory class, so the open/closed principle is broken.

We can improve the simple factory pattern to make it open for extension but closed for modification by using a mechanism to register new classes that will be instantiated when needed. There are two ways to achieve this:

  • Registering product class objects and instantiating them using reflection
  • Registering product objects and adding a newInstance method to each product that returns a new instance of the same class as itself

Simple factory with class registration using reflection

For this method, we are going to use a map to keep the product IDs along with their corresponding classes:

private Map<String, Class> registeredProducts = new HashMap<String,Class>();
Then, we add a method to register new vehicles:



public void registerVehicle(String vehicleId, Class vehicleClass)
{
registeredProducts.put(vehicleId, vehicleClass);
}


The create method becomes the following:

public Vehicle createVehicle(String type) throws InstantiationException, IllegalAccessException
{
Class productClass = registeredProducts.get(type);
return (Vehicle)productClass.newInstance();
}
In certain situations, working with reflection is either impossible or discouraged. Reflection requires a runtime permission that may not be present in certain environments. If performance is an issue, reflection may slow the program and so should be avoided.


Simple factory with class registration using Product.newInstance

In the previous code, we used reflection to instantiate new vehicles. If we have to avoid reflection, we can use a similar factory where to register the new vehicle classes the factory should be able to create. Instead of adding classes to the map, we are going to add instances of each type of object we want to register. Each product will be able to create a new instance of itself.

We start by adding an abstract method in the base Vehicle class:

abstract public Vehicle newInstance();
For each product, the method declared abstract in the base class must be implemented:
@Override
public Car newInstance()
{
return new Car();
}

In the factory class, we are going to change the map to keep the IDs of the objects along with the vehicle objects:

private Map<String, Vehicle> registeredProducts = new HashMap<String,Vehicle>();

Then we register a new type of vehicle by passing an instance of it:

public void registerVehicle(String vehicleId, Vehicle vehicle)
{
registeredProducts.put(vehicleId, vehicle);
}

We change the createVehicle method accordingly:

public AbstractProduct createVehicle(String vehicleId) 
{
return registeredProducts.get(vehicleId).newInstance();
}

Factory method pattern

The factory method pattern is an improvement upon the static factory. The factoryclass is made abstract and the code to instantiate specific products is moved to subclasses that implement an abstract method. This way, the factory class can be extended without being modified. The implementation of a factory method pattern is described in the following class diagram:

The factory method pattern is an improvement upon the static factory. The factoryclass is made abstract and the code to instantiate specific products is moved to subclasses that implement an abstract method. This way, the factory class can be extended without being modified. The implementation of a factory method pattern is described in the following class diagram:


It's time for some example code. Let's assume we have a car factory. At the moment, we produce two car models: a small sports car and a large family car. In our software, the customer can decide whether they want a small car or a large car. To start with, we are creating a Vehicle class with two subclasses: SportCar and SedanCar.

Now that we have the vehicle structure, let's build the abstract factory. Please note that the factory does not have any code to create new instances:

public abstract class VehicleFactory 
{
protected abstract Vehicle createVehicle(String item);
public Vehicle orderVehicle(String size, String color)
{
Vehicle vehicle = createVehicle(size);
vehicle.testVehicle();
vehicle.setColor(color);
return vehicle;
}
}

To add the code to create car instances, we subclass the VehicleFactory, creating a CarFactory. The car factory has to implement the createVehicle abstract method, which is invoked from the parent class. Practically, the VehicleFactory delegates the concrete vehicle's instantiation to the subclasses:

public class CarFactory extends VehicleFactory 
{
@Override
protected Vehicle createVehicle(String size)
{
if (size.equals("small"))
return new SportCar();
else if (size.equals("large"))
return new SedanCar();
return null;
}
}

In the client, we simply create the factory and create orders:

VehicleFactory carFactory = new CarFactory();
carFactory.orderVehicle("large", "blue");

At this point, we realize how much profit a car factory can bring. It's time to extend our business, and our market research tells us that there is a high demand for trucks. So let's build a TruckFactory:

public class TruckFactory extends VehicleFactory 
{
@Override
protected Vehicle createVehicle(String size)
{
if (size.equals("small"))
return new SmallTruck();
else if (size.equals("large"))
return new LargeTruck();
return null;
}
}

When an order is started, we use the following code:

VehicleFactory truckFactory = new TruckFactory();
truckFactory.orderVehicle("large", "blue");

Anonymous concrete factory

We continue the previous code by adding a BikeFactory from where customers can select a small bike or a large bike. We can do this without creating a separate class file; we can simply create an anonymous class that extends the VehicleFactory directly in the client code:

VehicleFactory bikeFactory = new VehicleFactory() 
{
@Override
protected Vehicle createVehicle(String size)
{
if (size.equals("small"))
return new MountainBike();
else if (size.equals("large"))
return new CityBike();
return null;
}
};
bikeFactory.orderVehicle("large", "blue");





















































Comments