A Case Study into Factory Design Pattern in Java
Factory method pattern is a creational pattern that uses factory methods to deal with the problem of creating objects without having to specify the exact class of the object that will be created.
- Wikipedia
Let’s say we have an OrderService class. This class will help us create an Order object based on the events — if there is a newOrderEvent, create an Order based on new order logic; if it is a cancelOrderEvent, create an Order based on cancel order logic.
In our OrderService class, we have instances for each type of OrderCreator— NewOrderCreator and CancelOrderCreator. Depending on which event we receive, we will call the corresponding instance to create an order for us.
public class OrderService {
private NewOrderCreator newOrderCreator;
private CancelOrderCreator cancelOrderCreator;
private Order order;
// Some Code
public void handleNewOrder(NewOrderEvent event){
order = newOrderCreator.create(event.getDetails());
}
public void handleCancelOrder(CancelOrderEvent event){
order = cancelOrderCreator.create(event.getDetails());
}
}
But is there a more clean way to do this?
Instead of preparing the instances beforehand, we can actually use a factory class that encapsulates how we decide the order creator.
public class OrderCreatorFactory {
public static OrderCreator getOrderCreator(Event event){
if (event instanceof NewOrderEvent){
return new NewOrderCreator();
}
else if (event instanceof CancelOrderCreator){
return new CancelOrderCreator();
}
return null;
}
}
In this Factory class, we abstracted order creators and events to interfaces — OrderCreator and Event. The getOrderCreator is a static method so we can just call the method without creating the factory instance. Depending on which event the object is an instance of, we will return the corresponding OrderCreator.
In the new OrderService class, we no longer need to worry about creating instances because this part has been delegated to the factory class. Therefore, we can refactor the existing code to this:
public class OrderService {
private OrderCreatorFactory orderCreatorFactory;
private Order order;
// Some Code
public void handleOrder(Event event){
order = orderCreatorFactory.getOrderCreator(event)
.create(event.getDetails());
}
}
We don’t have separate handlers to handle newOrder and cancelOrder anymore. Instead, we integrate them into a single “handleOrder” due to the advantage of abstraction. Depending on the event we receive, the factory class will help us instantiate the corresponding creator to create Order object for us.
In this way, if there is a need to create more types of orders, we only need to modify the factory class instead of creating more instances on OrderService class. This makes our code more extensible and clean.