Thursday, July 28, 2016

Abstract Factory Design Pattern


Abstract Factory Design Pattern is another flavour of Factory Design Pattern. This pattern can be considered as a “super factory” or “Factory of factories”.
The Abstract Factory design pattern is a creational pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes. This pattern allows you to produce objects that belong to a particular family, ensuring that the objects are compatible with each other and conform to a specific set of interfaces or classes.

Problem Statement:
For example, consider a garments factory specialized in creating trousers and shirts. Now the Parent company which is a famous Retail brand is now venturing into Gadget section. They are also planning to expand their Factories having one center in US and another one in UK. The client should be completely unaware of how the objects are created. What is the best design pattern we can use to resolve this requirement?

Solution:
To solve the above design problem we will use Abstract Factory Pattern. As mentioned earlier this is the super Factory. The above problem cannot be resolved efficiently using the Factory method pattern as this involves multiple Factories and products which are related to the parent company or dependent.
Now let’s have a look at our real life Garment Factory example and what’s the difference than the Factory Method pattern.


Example:
In the above real life example, the RetailFactory is AbstractFactory class which now has multiple Concrete factories (UKFactory and USFactory) in various locations like US and UK specialized in creating multiple products like Shirt/Laptop and Trouser/Mobile respectively. In this example we have also created another additional class called FactoryMaker which takes the choice of Factory from the client and then delegates the job to appropriate Factory classes accordingly. The client is completely unaware of how this processing is done and has reference to only the RetailFactory interface and GarmentType and GadgetType interface. This loose coupling also helps in terms of addition of multiple Concrete Products without much change in the client code.

Benefits:
Use of this pattern makes it possible to interchange the concrete classes without changing the client code even at run time.

Here are several real-time use cases for the Abstract Factory Method pattern:

1. Database Access Layers

Context: Applications that support multiple database systems (e.g., MySQL, PostgreSQL, Oracle) need a way to create database connections and queries that are specific to each database type.

Example: A data access layer uses the Abstract Factory Method pattern to create different sets of database connections and query objects based on the database system being used.

2. Document Generation Systems

Context: Document generation systems that produce different types of documents (e.g., PDF, Word, HTML) need a way to handle different document formats and their components.

Example: A document generation system uses the Abstract Factory Method pattern to create documents and pages specific to each format.

3. Automotive Manufacturing

Context: In automotive manufacturing, different types of vehicles (e.g., sedans, SUVs) require different sets of components (e.g., engines, tires, interiors).

Example: An automotive factory uses the Abstract Factory Method pattern to create different sets of components for each vehicle type.

 

Source code for Abstract Factory example:


GarmentType.java
/**
 * @author TeachtoJava
 *
 */
public interface GarmentType {
            String print();
}

GadgetType.java
public interface GadgetType {
            String print();
}

RetailFactory.java
/**
 * Factory class is the abstract class which will
 *  be referred by client. All the concrete classes needs to
 *  implement the abstract factory method.
 * @author TeachtoJava
 */
public interface RetailFactory {
  GarmentType createGarments(String garmentSelection);
  GadgetType createGadgets(String gadgetSelection);
 }

Shirt.java
public class Shirt implements GarmentType {
            @Override
            public String print() {
                        System.out.println("Shirt Created");
                        return "Shirt";
            }
}

Trouser.java
public class Trouser implements GarmentType {
            @Override
            public String print() {
                        System.out.println("Trouser Created");
                        return "Trouser";
            }

}

Laptop.java
public class Laptop implements GadgetType {

            @Override
            public String print() {
                        System.out.println("Laptop Created");
                        return "Laptop";
            }

}

Mobile.java
public class Mobile implements GadgetType {

            @Override
            public String print() {
                        System.out.println("Mobile Created");
                        return "Mobile";
            }

}

UKFactory.java
public class UKFactory implements RetailFactory{
            public  GarmentType createGarments(String garmentSelection) {
                        if (garmentSelection.equalsIgnoreCase("Trouser")) {
                                    return new Trouser();
                        }
                        throw new IllegalArgumentException("Selection doesnot exist");
            }

           
            public GadgetType createGadgets(String gadgetSelection) {
                        if (gadgetSelection.equalsIgnoreCase("Mobile")) {
                                    return new Mobile();
                        }
                        throw new IllegalArgumentException("Selection doesnot exist");
            }
}

USFactory.java
public class USFactory implements RetailFactory{
            public GarmentType createGarments(String garmentSelection) {
                        if (garmentSelection.equalsIgnoreCase("Shirt")) {
                                    return new Shirt();
                        }
                        throw new IllegalArgumentException("Selection doesnot exist");
            }

            public GadgetType createGadgets(String gadgetSelection) {
             if (gadgetSelection.equalsIgnoreCase("Laptop")) {
                                    return new Laptop();
                        }
                        throw new IllegalArgumentException("Selection doesnot exist");
            }
}

FactoryMaker.java
public class FactoryMaker {
 private static RetailFactory abstractFactory = null;
 static RetailFactory getFactory(String choice){
            if(choice.equalsIgnoreCase("UK")){
                        abstractFactory = new UKFactory();
            } else if(choice.equalsIgnoreCase("US")){
                        abstractFactory = new USFactory();
            }
            return abstractFactory;
 }
 
}

Client.java
public class Client {

            public static void main(String[] args) {
           
                        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
                        String garmentSelection = null;
                        String gadgetSelection = null;
                        String countryChoice = null;
                        try {
                                    System.out.println("1. Enter your selection from Trouser/Shirt:\n");
                                    garmentSelection = br.readLine();
                                    System.out.println("2. Enter your selection from Laptop/Mobile:\n");
                                    gadgetSelection = br.readLine();
                                    System.out.println("3. Enter your Country Selection from UK/US:\n");
                                    countryChoice = br.readLine();
                        } catch (IOException e) {
                                    e.printStackTrace();
                        }
                       
                        RetailFactory objRetailFactory = FactoryMaker.getFactory(countryChoice);
                        System.out.println("Your choice of country is " + countryChoice);
                        GarmentType objGarmentType = objRetailFactory.createGarments(garmentSelection);
                        System.out.println(objGarmentType.print());
                        GadgetType objGadgetType = objRetailFactory.createGadgets(gadgetSelection);
                        System.out.println(objGadgetType.print());

            }

}






No comments:

Post a Comment