JAVA design pattern factory pattern

Keywords: Java

Factory Pattern of JAVA design pattern

1. Introduction to factory mode

Factory pattern is used to create objects, which decouples customers from specific product objects.

2. Factory model classification

Here's an example of making coffee to start the factory pattern design journey.

We know that coffee is just a kind of generalization. When ordering coffee, we need to specify specific coffee types: American coffee, cappuccino, latte, etc.

/**
 * 
 * Latte, American coffee and cappuccino are all products of coffee family
 * Coffee as an abstract concept
 * @author Lsj
 *
 */
public abstract class Coffee {

    /**
     * Get the coffee name
     * @return
     */
    public abstract String getName();
    
}


/**
 * Cafe Americano
 * @author Lsj
 *
 */
public class Americano extends Coffee {

    @Override
    public String getName() {
        return "Cafe Americano";
    }

}


/**
 * Cappuccino
 * @author Lsj
 *
 */
public class Cappuccino extends Coffee {

    @Override
    public String getName() {
        return "Cappuccino";
    }

}


/**
 * Latte
 * @author Lsj
 *
 */
public class Latte extends Coffee {

    @Override
    public String getName() {
        return "Latte";
    }

}

2.1 simple factory

In fact, a simple factory can not be regarded as a design pattern. It introduces the concept of creator, pulls the instantiated code from the application code, and only deals with the details of the created object in the static method of the creator class. If the subsequent created instance needs to be changed, only the creator class needs to be modified,

However, there are some limitations because static methods are used to get objects, so that they can not dynamically change the creation behavior in different ways during operation.

/**
 * Simple factory - used to create different types of coffee instances
 * @author Lsj
 *
 */
public class SimpleFactory {
    
    /**
     * Get the Coffee instance object by type
     * @param type Coffee type
     * @return
     */
    public static Coffee createInstance(String type){
        if("americano".equals(type)){
            return new Americano();
        }else if("cappuccino".equals(type)){
            return new Cappuccino();
        }else if("latte".equals(type)){
            return new Latte();
        }else{
            throw new RuntimeException("type["+type+"]Unrecognized type, no matching to instantiable object!");
        }
    }
    
    public static void main(String[] args) {
        Coffee latte = SimpleFactory.createInstance("latte");
        System.out.println("The coffee instance created is:" + latte.getName());
        Coffee cappuccino = SimpleFactory.createInstance("cappuccino");
        System.out.println("The coffee instance created is:" + cappuccino.getName());
    }

}

2.2 factory method mode

It defines an interface for creating objects, but the subclass decides which class to instantiate. The factory method makes the class postpone the instantiation to the subclass.

Scenario extension: coffee factories in different regions are subject to the influence of environment, raw materials and other factors, resulting in a limited variety of coffee. Chinese coffee factories can only make cappuccino and latte, while American coffee factories can only make American coffee and latte.

/**
 * Define an abstract Coffee Factory
 * @author Lsj
 */
public abstract class CoffeeFactory {
    
    /**
     * Produce coffee that can be made
     * @return
     */
    public abstract Coffee[] createCoffee();

}


/**
 * China Coffee Factory
 * @author Lsj
 *
 */
public class ChinaCoffeeFactory extends CoffeeFactory {

    @Override
    public Coffee[] createCoffee() {
        // TODO Auto-generated method stub
        return new Coffee[]{new Cappuccino(), new Latte()};
    }

}


/**
 * American coffee factory
 * @author Lsj
 *
 */
public class AmericaCoffeeFactory extends CoffeeFactory {

    @Override
    public Coffee[] createCoffee() {
        // TODO Auto-generated method stub
        return new Coffee[]{new Americano(), new Latte()};
    }

}


/**
 * Factory method test
 * @author Lsj
 *
 */
public class FactoryMethodTest {

    static void print(Coffee[] c){
        for (Coffee coffee : c) {
            System.out.println(coffee.getName());
        }
    }
    
    public static void main(String[] args) {
        CoffeeFactory chinaCoffeeFactory = new ChinaCoffeeFactory();
        Coffee[] chinaCoffees = chinaCoffeeFactory.createCoffee();
        System.out.println("Coffee factories in China can produce:");
        print(chinaCoffees);
        CoffeeFactory americaCoffeeFactory = new AmericaCoffeeFactory();
        Coffee[] americaCoffees = americaCoffeeFactory.createCoffee();
        System.out.println("Coffee plants in the United States can produce:");
        print(americaCoffees);
    }
}

2.3 Abstract Factory

Provides an interface to create a family of related or dependent objects without specifying specific classes.

Continue to extend in the above scenario: the coffee factory is bigger and stronger, introducing new types of drinks: tea, carbonated drinks. Chinese factories can only make coffee and tea, while American factories can only make coffee and carbonated drinks.

If the above factory method is used, besides the corresponding product entity class, two abstract factories (tea manufacturing factory and carbonated beverage manufacturing factory) and four specific factories need to be added. With the increase of products, it will lead to class explosion.

So here comes a concept product family. In this case, different drinks form our drink family. The drink family begins to take the responsibility of the creator and be responsible for manufacturing different products.

/**
 * Abstract beverage product family manufacturing plant
 * @author Lsj
 *
 */
public interface AbstractDrinksFactory {

    /**
     * Make coffee
     * @return
     */
    Coffee createCoffee();
    
    /**
     * Making tea
     * @return
     */
    Tea createTea();
    
    /**
     * Making carbonated drinks
     * @return
     */
    Sodas createSodas();
}


/**
 * China Beverage Factory
 * Making coffee and tea
 * @author Lsj
 *
 */
public class ChinaDrinksFactory implements AbstractDrinksFactory {

    @Override
    public Coffee createCoffee() {
        // TODO Auto-generated method stub
        return new Latte();
    }

    @Override
    public Tea createTea() {
        // TODO Auto-generated method stub
        return new MilkTea();
    }

    @Override
    public Sodas createSodas() {
        // TODO Auto-generated method stub
        return null;
    }

}


/**
 * American beverage manufacturing plant
 * Making coffee and carbonated drinks
 * @author Lsj
 *
 */
public class AmericaDrinksFactory implements AbstractDrinksFactory {

    @Override
    public Coffee createCoffee() {
        // TODO Auto-generated method stub
        return new Latte();
    }

    @Override
    public Tea createTea() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    public Sodas createSodas() {
        // TODO Auto-generated method stub
        return new CocaCola();
    }

}


/**
 * Abstract factory test class
 * @author Lsj
 *
 */
public class AbstractFactoryTest {
    
    static void print(Drink drink){
        if(drink == null){
            System.out.println("Products:--" );
        }else{
            System.out.println("Products:" + drink.getName());
        }
    }
    
    public static void main(String[] args) {
        AbstractDrinksFactory chinaDrinksFactory = new ChinaDrinksFactory();
        Coffee coffee = chinaDrinksFactory.createCoffee();
        Tea tea = chinaDrinksFactory.createTea();
        Sodas sodas = chinaDrinksFactory.createSodas();
        System.out.println("China beverage factory has the following products:");
        print(coffee);
        print(tea);
        print(sodas);
        
        AbstractDrinksFactory americaDrinksFactory = new AmericaDrinksFactory();
        coffee = americaDrinksFactory.createCoffee();
        tea = americaDrinksFactory.createTea();
        sodas = americaDrinksFactory.createSodas();
        System.out.println("American beverage factories have the following products:");
        print(coffee);
        print(tea);
        print(sodas);
    }

}

3. summary

Simple factory: it's not really a design pattern, but it can decouple the client program from the concrete class.

Factory method: use inheritance to delegate the creation of objects to subclasses and subclasses to implement the creation method, which can be regarded as the case where there is only a single product in the abstract factory pattern.

Abstract factory: make the creation of objects be implemented in the methods exposed by the factory interface.

Factory pattern can help us to program for abstract / interface, rather than specific class, and use it in different scenarios.

Reference books:

HeadFirst design mode

Posted by Irap on Sun, 03 Nov 2019 02:02:50 -0800