Simple factory pattern and abstract factory pattern

Simple factory pattern and abstract factory pattern

No BB, come to demand design directly

A pizza shop now needs to produce a variety of color pizza for customers to use. In order to meet the needs of producing a variety of color pizza, the first idea in our mind is to use the factory model to create different pizza.

First look at the rough design of the sketch


Then you want the function in the figure. At least 3 classes are required. One is the green pizza entity class, the red pizza entity class, and the pizza factory class (I inherit the pizza entity class here, and add an additional class).

Pizza has name, color, price, description

@Data annotation comes from lombok. It can reduce the writing of set, get and toString methods, but it can still use these methods

package cn.withme.pattern.abstractFactory.simple;

import lombok.Data;

import java.util.List;

@Data 
public class Pissa {
    protected String name ;
    protected List<String> colors;
    protected Double price;

    public String getDesc () {
        return null;
    }
}

package cn.withme.pattern.abstractFactory.simple;

import cn.withme.pattern.abstractFactory.enums.ColorEnum;
import lombok.Data;

import java.util.Arrays;

/**
 * @className: GreenPissa
 * @description: Green pizza
 * @author: liming
 * @date: 2020/1/16
 **/
@Data
public class GreenPissa extends  Pissa{

    public GreenPissa() {
        this.colors = Arrays.asList(ColorEnum.GREEN.getDesc());
        this.name = "One contains"+this.colors+"Pizza";
        this.price = 10.0;
    }

    @Override
    public String getDesc () {
        return this.name+",\t Price:"+this.price;
    }
}

package cn.withme.pattern.abstractFactory.simple;

import cn.withme.pattern.abstractFactory.enums.ColorEnum;
import lombok.Data;

import java.util.Arrays;

/**
 * @className: GreenPissa
 * @description: Green pizza
 * @author: liming
 * @date: 2020/1/16
 **/
@Data
public class RedPissa extends  Pissa{

    public RedPissa() {
        this.colors = Arrays.asList(ColorEnum.RED.getDesc());
        this.name = "One contains"+this.colors+"Pizza";
        this.price = 10.0;
    }

    @Override
    public String getDesc () {
        return this.name+",\t Price:"+this.price;
    }
}

package cn.withme.pattern.abstractFactory.enums;

/**
 * @Description: Color enumeration class
 * @Author: liming
 * @date 2020 January 16, 2016
 */
public enum ColorEnum {
    RED("red","Red"),
    GREEN("green","green"),
    ;

    private String code;
    private String desc ;

    ColorEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public static String getTypeNameByType (String type){
        for (ColorEnum c : ColorEnum.values()) {
            if (c.getCode().equalsIgnoreCase(type)) {
                return c.getDesc();
            }
        }
        return null;
    }
}

Pizza production factory. Here, through the create method, you can generate different colors of pizza

package cn.withme.pattern.abstractFactory.simple;

/**
 * @className: PissaFactory
 * @description: Simple pizza factory
 * @author: liming
 * @date: 2020/1/16
 **/
public class PissaFactory {

    public Pissa create(String type) {
        Pissa p;
        switch (type) {
            case "green":
                p = new GreenPissa();
                break;
            case "red":
                p = new RedPissa();
                break;
             //Omit n case s
            default:
                p = new Pissa();
        }
        return p;
    }
}

Test it.

package cn.withme.pattern.abstractFactory.simple;

/**
 * @className: SimplePissaTest
 * @description: Pizza test
 * @author: liming
 * @date: 2020/1/16
 **/
public class SimplePissaTest {

    public static void main(String[] args) {
        PissaFactory factory = new PissaFactory();
        Pissa pissa = factory.create("red");
        print(pissa); //A pizza containing [red], price: 10.0
    }

    private static void print(Pissa pissa) {
        System.out.println(null == pissa ? "" :pissa.getDesc());
    }
}

Then the simplest pizza factory has been realized.

If you think of if less and switch case, you can modify PissaFactory.

package cn.withme.pattern.abstractFactory.simple;

import java.util.HashMap;
import java.util.Map;

/**
 * @className: PissaFactory
 * @description: Simple pizza factory
 * @author: liming
 * @date: 2020/1/16
 **/
public class PissaFactory {

    private static final Map<String,Pissa> pissaMap = new HashMap<>();

    static {
        pissaMap.put("green", new GreenPissa());
        pissaMap.put("red", new RedPissa());
    }

    public Pissa create(String type) {
       return pissaMap.get(type);
    }

}

In this way, if less and switch case are omitted.

The business of pizza shops in the back is getting better and better, and many franchisees all over the country come to invest.

So we started to make pizza again.

As more and more franchisees, the original pizza shop can not meet the needs of customers everywhere. So franchisees want to add something in their own area.

So hard pressed programmers began to work overtime.

If you simply modify the code in this block

 switch (type) {
            case "green":
                p = new GreenPissa();
                break;
            case "red":
                p = new RedPissa();
                break;
             //Omit n case s
            default:
                p = new Pissa();
        }

So there will be more and more codes in this area. Moreover, if there are franchisees in Changsha who produce red pizza, they need to label "Changsha". Franchisees in Guangzhou produce red pizza, but they need to label "Guangzhou".

The current design can no longer meet the needs of pizza production.

Because the original pizza factory was too large. So now we have to produce all kinds of pizza. In short, the franchisees in a certain region produce their own pizza in that region. It's right not to affect each other.

The ideal design is as follows:

It needs to be labeled. So add a label enumeration class

package cn.withme.pattern.abstractFactory.enums;

/**
 * @Description: Location enumeration class
 * @Author: liming
 * @date 2020 January 16, 2016
 */
public enum LocationEnum {
    CHANGSHA("changsha","Changsha"),
    GUANGZHOU("guangzhou","Guangzhou"),
    ;

    private String code;
    private String desc ;

    LocationEnum(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getDesc() {
        return desc;
    }

    public void setDesc(String desc) {
        this.desc = desc;
    }

    public static String getTypeNameByType (String type){
        for (LocationEnum c : LocationEnum.values()) {
            if (c.getCode().equalsIgnoreCase(type)) {
                return c.getDesc();
            }
        }
        return null;
    }
}

//This class is the parent class of Changsha franchisee and Guangdong franchisee. If other franchisees add in later, you can directly inherit this class

package cn.withme.pattern.abstractFactory.advance.factory;

import cn.withme.pattern.abstractFactory.advance.domain.Pissa;

/**
 * @className: PissaAbstractFactory
 * @description: Abstract pizza factory
 * @author: liming
 * @date: 2020/1/16
 **/
public abstract class PissaAbstractFactory {
    abstract Pissa create(String type);
}

Changsha franchisee and Guangdong franchisee factories are as follows:

package cn.withme.pattern.abstractFactory.advance.factory;

import cn.withme.pattern.abstractFactory.advance.domain.ChangshaGreenPissa;
import cn.withme.pattern.abstractFactory.advance.domain.ChangshaRedPissa;
import cn.withme.pattern.abstractFactory.advance.domain.Pissa;
import cn.withme.pattern.abstractFactory.enums.LocationEnum;

/**
 * @className: ChangshaPissaFactory
 * @description:
 * @author: liming
 * @date: 2020/1/16
 **/
public class ChangshaPissaFactory extends PissaAbstractFactory{

    public static String LOCALTION = LocationEnum.CHANGSHA.getDesc();


    @Override
    Pissa create(String type) {
        Pissa p;
        switch (type) {
            case "green":
                p = new ChangshaGreenPissa();
                break;
            case "red":
                p = new ChangshaRedPissa();
                break;
            //Omit n case s
            default:
                p = new Pissa();
        }
        return p;
    }
}

package cn.withme.pattern.abstractFactory.advance.factory;

import cn.withme.pattern.abstractFactory.advance.domain.GuangzhouGreenPissa;
import cn.withme.pattern.abstractFactory.advance.domain.GuangzhouRedPissa;
import cn.withme.pattern.abstractFactory.advance.domain.Pissa;
import cn.withme.pattern.abstractFactory.enums.LocationEnum;

/**
 * @className: ChangshaPissaFactory
 * @description:
 * @author: liming
 * @date: 2020/1/16
 **/
public class GuangZhouPissaFactory extends PissaAbstractFactory{

    public static String LOCALTION = LocationEnum.GUANGZHOU.getDesc();

    @Override
    Pissa create(String type) {
        Pissa p;
        switch (type) {
            case "green":
                p = new GuangzhouGreenPissa();
                break;
            case "red":
                p = new GuangzhouRedPissa();
                break;
            //Omit n case s
            default:
                p = new Pissa();
        }
        return p;
    }
}

The original PissaFactory was changed to:

package cn.withme.pattern.abstractFactory.advance.factory;


import cn.withme.pattern.abstractFactory.advance.domain.Pissa;

/**
 * @className: PissaFactory
 * @description: Simple pizza factory
 * @author: liming
 * @date: 2020/1/16
 **/
public class PissaFactory {

    private PissaAbstractFactory abstractFactory;

    public PissaFactory(PissaAbstractFactory abstractFactory) {
        this.abstractFactory = abstractFactory;
    }

    public Pissa create(String type) {
        Pissa pissa = abstractFactory.create(type);
        return pissa;
    }
}

Changsha greenpissa, Changsha redpissa, Guangzhou greenpissa and Guangzhou redpissa don't change much. Paste one class and the rest are almost the same

package cn.withme.pattern.abstractFactory.advance.domain;

import cn.withme.pattern.abstractFactory.advance.factory.ChangshaPissaFactory;
import cn.withme.pattern.abstractFactory.enums.ColorEnum;
import lombok.Data;

import java.util.Arrays;

/**
 * @className: GreenPissa
 * @description: Green pizza
 * @author: liming
 * @date: 2020/1/16
 **/
@Data
public class ChangshaGreenPissa extends  Pissa{

    public ChangshaGreenPissa() {
        this.colors = Arrays.asList(ColorEnum.GREEN.getDesc());
        this.name = "One contains"+this.colors+"Pizza";
        this.price = 10.0;
    }

    @Override
    public String getDesc () {
        return this.name+",\t Price:"+this.price+",\t Production location:" + ChangshaPissaFactory.LOCALTION;
        //Production location added here
    }
}

So if it's such a transformation. In the future, more franchisees can adapt to this mode.

Write a test class:

package cn.withme.pattern.abstractFactory.advance;

import cn.withme.pattern.abstractFactory.advance.domain.Pissa;
import cn.withme.pattern.abstractFactory.advance.factory.GuangZhouPissaFactory;
import cn.withme.pattern.abstractFactory.advance.factory.PissaFactory;

/**
 * @className: AdvancePissaFactory
 * @description: Test class
 * @author: liming
 * @date: 2020/1/16
 **/
public class AdvancePissaFactoryTest {

    public static void main(String[] args) {
        PissaFactory pissaFactory = new PissaFactory(new GuangZhouPissaFactory());
        Pissa pissa = pissaFactory.create("red");
        System.out.println(pissa.getDesc());
    }
}

In this way, the minimum code can be changed and different franchisees (products) can be adapted.

To summarize: the difference between simple factory pattern and abstract factory pattern

Simple factory pattern is good for generating a small number of objects, but there is no way to distinguish multiple products (if you want to distinguish products in simple factory pattern, it will only bring more if else).

Moreover, Lu Xun said that if too many people modify the same category, they will surely correct others' mistakes. If each franchisee only maintains its own part of functions, the probability of mistakes will be relatively reduced, and the influence will not spread to other franchisees.)

Code uploaded to github

96 original articles published, 42 praised, 250000 visitors+
Private letter follow

Tags: Java Lombok less REST

Posted on Thu, 16 Jan 2020 05:39:01 -0500 by supermerc