Wednesday, July 6, 2022

Creational Design Patterns # Factory Method

  • Factory Method is a creational design pattern that provides an interface for creating objects in a superclass but allows subclasses to alter the type of objects that will be created.

  • Problem

    Imagine that you’re creating a logistics management application. The first version of your app can only handle transportation by trucks, so the bulk of your code lives inside the Truck class.

    After a while, your app becomes pretty popular. Each day you receive dozens of requests from sea transportation companies to incorporate sea logistics into the app



    Great news, right? But how about the code? At present, most of your code is coupled to the Truckclass. Adding Ships into the app would require making changes to the entire codebase. 

    Moreover, if later you decide to add another type of transportation to the app, you will probably need to make all of these changes again.

    As a result, you will end up with pretty nasty code, riddled with conditionals that switch the app’s behavior depending on the class of transportation objects.


    Solution


    The Factory Method pattern suggests that you replace direct object construction calls (using the new operator) with calls to a special factory method.
     
    Don’t worry: the objects are still created via the new operator, but it’s being called from within the factory method. Objects returned by a factory method are often referred to as products.

    At first glance, this change may look pointless: we just moved the constructor call from one part of the program to another.


    However, consider this: now you can override the factory method in a subclass and change the class of products being created by the method.

    There’s a slight limitation though: subclasses may return different types of products only if these products have a common base class or interface. 

    Also, the factory method in the base class should have its return type declared as this interface.

    For example, both Truck and Ship classes should implement the Transportinterface, which declares a method called deliver.

    Each class implements this method differently: trucks deliver cargo by land, ships deliver cargo by sea. The factory method in the RoadLogistics class returns truck objects, whereas the factory method in the SeaLogistics class returns ships.


    The code that uses the factory method (often called the client code) doesn’t see a difference between the actual products returned by various subclasses.

    The client treats all the products as abstract Transport. The client knows that all transport objects are supposed to have the delivermethod, but exactly how it works isn’t important to the client.

    Structure


    Pros and Cons




    Here is a complete code example of the Factory pattern in Java:

    Factory Design Pattern Super Class
    public abstract class Computer { public abstract String getRAM(); public abstract String getHDD(); public abstract String getCPU(); @Override public String toString(){ return "RAM= "+this.getRAM()+", HDD="+this.getHDD()+", CPU="+this.getCPU(); } }

    Factory Design Pattern Sub Classes
    public class PC extends Computer { private String ram; private String hdd; private String cpu; public PC(String ram, String hdd, String cpu){ this.ram=ram; this.hdd=hdd; this.cpu=cpu; } @Override public String getRAM() { return this.ram; } @Override public String getHDD() { return this.hdd; } @Override public String getCPU() { return this.cpu; } }

    Notice that both the classes are extending Computer super class
    public class Server extends Computer { private String ram; private String hdd; private String cpu; public Server(String ram, String hdd, String cpu){ this.ram=ram; this.hdd=hdd; this.cpu=cpu; } @Override public String getRAM() { return this.ram; } @Override public String getHDD() { return this.hdd; } @Override public String getCPU() { return this.cpu; } }

    Factory Class

    Now that we have super classes and sub-classes ready, we can write our factory class. Here is the basic implementation.

    public class ComputerFactory { public static Computer getComputer(String type, String ram, String hdd, String cpu){ if("PC".equalsIgnoreCase(type)) return new PC(ram, hdd, cpu); else if("Server".equalsIgnoreCase(type)) return new Server(ram, hdd, cpu); return null; }

    Here is a simple test client program that uses above factory design pattern implementation.
    public class TestFactory { public static void main(String[] args) { Computer pc = ComputerFactory.getComputer("pc","2 GB","500 GB","2.4 GHz"); Computer server = ComputerFactory.getComputer("server","16 GB","1 TB","2.9 GHz"); System.out.println("Factory PC Config::"+pc); System.out.println("Factory Server Config::"+server); } }

    Output of above program is:
    Factory PC Config::RAM= 2 GB, HDD=500 GB, CPU=2.4 GHz Factory Server Config::RAM= 16 GB, HDD=1 TB, CPU=2.9 GHz

    You may also like

    Kubernetes Microservices
    Python AI/ML
    Spring Framework Spring Boot
    Core Java Java Coding Question
    Maven AWS