DEV Community

Nishchya Verma
Nishchya Verma

Posted on

Creational Patterns : Factory Method

Creational Patterns

Factory Method

Factory pattern encapsulates object creation letting the subclasses decide what object to create. It is the most used design pattern.

A framework needs to standardize the architectural model for a range of applications but allow for individual applications to define their own domain objects and provide for their instantiation. In simple words, In Factory Method a superclass specifies all standard and generic behavior, and then delegates the creation details to subclasses that are supplied by the client. This superclass is called a Factory. Factories handle the details of object creation. This way it makes the design more customizable.
image

Why do we need Factory Method?

The Factory Method defines an interface for creating objects, but let’s subclasses decide which classes to instantiate.

When we use new operator, we are instantiating a concrete class. There is a difference between requesting an object and creating one. The new operator always creates an object and fails to encapsulate object creation. A Factory Method enforces that encapsulation and allows an object to be requested without inextricable coupling to the act of creation.

Lets consider an example,

Pizza pizzaOrder;

if(margerita){
  pizzaOrder = new Margerita();
}
else if(country){
  pizzaOrder = new CountryFeast();
}
else if(corn){
 pizzaOrder = new CornCheese();
}

Enter fullscreen mode Exit fullscreen mode

In above example Pizza is an interface that helps us keep code flexible. However, we must create an instance of a concrete class. And since we have a bunch of different Pizza classes, and we do not know until runtime which one we need to instantiate.

Now this is possible that above code snippet may exist in your code base at several locations in multiple classes, and when you are required to add or remove a type of Pizza Class it will make code update more difficult, time consuming and prone to errors.

To solve this issue, we use Factory Method pattern.

Lets explore Factory Method Pattern.

Note- The examples discussed will be in Java.
Suppose the client code needs a new product(object). Now client have two options, first is that it can use new operator to create the Product. However when implementing Factory Pattern our client code will instead ask the factory object for a new Product by providing it the information regarding the type of product it need.

Once the factory object will receive the necessary information regarding the Product type needed, factory will instantiate the new concrete Product and then return to the client the newly created Product(casted to abstract Product class). The client will use the products as abstract products without being aware about their concrete implementation.

Let's consider the following example for better understanding,
A coffee-outlet pos application works with different types of Coffee. Here the Menu Class is the client and different types of coffee in the menu are the Products. All coffee products like (Espresso, Latte, Mocha) are derived from an abstract Coffee class(or interface). The Coffee class(or interface) defined the withSugar and withMilk methods which must be implemented by all the 3 Product classes. Now suppose a Latte Coffee is selected from the Menu. the code recieves the type of coffee, ie. Latte as a String paramenter and it asks our Factory Object to create a new concrete Object ie. Latte. The factory creates a new Latte and returns it to the calling object casted to an abstract Coffee class. Then the code uses the object as casted to the abstract class without being aware of the concrete object type.

The core advantage of implementing Factory Pattern is that new coffee products can be added without changing a single line of code in the framework(the client code that uses the coffee from the factory).

Implementation

Lets discuss certain factory implementations that allow adding new products without even modifying the factory class.

Suppose you own a Logistic Business. You provide logistics solutions via trucks. In your application the bulk of your code lives inside the Truck class. Now you also want to manage logistics via Ships.

Since most of your code is coupled to the Truck class. Adding Ships into the app would require making changes to the entire codebase. Same apply if in future you want to add Airplane.

Your app’s will be filled with conditional statements that will switch the behavior of the application depending on the class of transportation objects (Ships, Trucks, etc).

Lets solve above issue by implementing Factory Method Pattern. Factory method suggest that you replace direct object construction calls (using the new operator) with calls to a special factory method. Now the objects are still created via the new operator, but it’s being called from within the factory method inside the factory object. Objects returned by a factory method are often referred to as products.

First we declare a Transport interface. This is the Product interface that we discussed earlier.

public interface Transport {
    public String deliverBy();
}
Enter fullscreen mode Exit fullscreen mode

Now we will declare two concrete products ie, Ship and Truck which implements Transport interface.

public class Ship implements Transport {
    public String deliverBy(){
        return "Ship deliver logistics by Sea";
    }
}

public class Truck implements Transport{
    public String deliverBy(){
        return "Truck deliver logistics by Road.";
    }
}
Enter fullscreen mode Exit fullscreen mode

Now once we have our concrete product classes and product interface now its time to setup our Factory in this example referred as Logistics.

public abstract class Logistics{
    public Transport createTransport(String type){

    }
    abstract Transport create(String type);
}

public class LandLogistics extends Logistics{
    public Transport create(String type){
        return new Truck();
    }
    public void deliveryBy(){
        System.out.println("Delivery by Road!");
    }
}

public class SeaLogistics extends Logistics{
    public Transport create(String type){
        return new Ship();
    }
    public void deliveryBy(){
        System.out.println("Delivery by Sea!");
    }
}
Enter fullscreen mode Exit fullscreen mode

Once we have our abstract factory class (Logistics) along with the two concrete factory classes (SeaLogistics and LandLogistics) we can use the above in our calling code as,

...
    Logistics log=null;
    if(input=="Sea"){
        log = new SeaLogistics();
    }
    else if(input=="Land"){
        log = new LandLogistics();
    }
    Transport transport = log.create();
    transport.deliveryBy();
...
Enter fullscreen mode Exit fullscreen mode

We will be discussing about other Creational patterns in the upcoming posts. Next will be Abstract Factory Pattern.

Stay tuned!

Note - Be part of the discussion and also leave a heart if you found it helpful.

Discussion (0)