簡單工廠模式和抽象工廠模式

簡單工廠模式和抽象工廠模式

不BB,直接來需求設計

一個披薩店現在需要生產多種顏色的披薩供顧客使用,我們爲了滿足生產多種顏色的披薩生產,腦海裏面第一想法是使用工廠模式來創建不同的披薩。

先看草圖的大致設計

在這裏插入圖片描述
那麼想要圖中的功能。至少需要3個類。一個是綠顏色披薩實體類,紅顏色披薩實體類,還有一個披薩工廠類(我這裏將披薩的實體類做了一下繼承,多加了一個類)。

披薩擁有名字,顏色,價格,描述

@Data 註解來自於lombok,可以減少set,get,toString方法的編寫,但是還是能夠使用這些方法

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: 綠色披薩
 * @author: liming
 * @date: 2020/1/16
 **/
@Data
public class GreenPissa extends  Pissa{

    public GreenPissa() {
        this.colors = Arrays.asList(ColorEnum.GREEN.getDesc());
        this.name = "一個包含"+this.colors+"的披薩";
        this.price = 10.0;
    }

    @Override
    public String getDesc () {
        return this.name+",\t 價格:"+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: 綠色披薩
 * @author: liming
 * @date: 2020/1/16
 **/
@Data
public class RedPissa extends  Pissa{

    public RedPissa() {
        this.colors = Arrays.asList(ColorEnum.RED.getDesc());
        this.name = "一個包含"+this.colors+"的披薩";
        this.price = 10.0;
    }

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

package cn.withme.pattern.abstractFactory.enums;

/**
 * @Description: 顏色枚舉類
 * @Author: liming
 * @date 2020年01月16日
 */
public enum ColorEnum {
    RED("red","紅色"),
    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;
    }
}

披薩生產工廠,這裏通過create方法,可以生成不同顏色的披薩

package cn.withme.pattern.abstractFactory.simple;

/**
 * @className: PissaFactory
 * @description: 簡單的披薩生產工廠
 * @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;
             //省略n個case
            default:
                p = new Pissa();
        }
        return p;
    }
}

測試一下

package cn.withme.pattern.abstractFactory.simple;

/**
 * @className: SimplePissaTest
 * @description: 披薩測試
 * @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); //一個包含[紅色]的披薩,	 價格:10.0
    }

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

那麼最簡單的披薩生產工廠就已經實現了。

如果覺得if lese 和 switch case,那麼可以將PissaFactory修改一下。

package cn.withme.pattern.abstractFactory.simple;

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

/**
 * @className: PissaFactory
 * @description: 簡單的披薩生產工廠
 * @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);
    }

}

這樣就省略了if lese 和 switch case

後面披薩店的生意越來越好,全國許多加盟商都來投資。

於是又開始生產披薩。

由於加盟商越來越多,原來的披薩店不能滿足各地的顧客需求。所以加盟商們想在自己的區域可以加一些自己的東西。

於是乎苦逼的程序員們開始加班改。

如果單純的修改這一塊的代碼

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

那麼勢必這一塊的代碼會越來越多,而且如果有長沙的加盟商生產紅色的披薩,但是需要打上"長沙"兩個字標籤,廣州的加盟商生產紅色的披薩,但是需要打上"廣州"兩個字標籤。

目前的設計已經不能滿足披薩的生產需求了。

因爲原來的披薩生產工廠範圍太大了。所以現在必須所有披薩生產的範圍,簡而言之就是某個地區的加盟商就生產自己那個地區的披薩。互不影響纔對。

理想設計如下:

在這裏插入圖片描述

由於需要帶上標籤。所以加一個標籤枚舉類

package cn.withme.pattern.abstractFactory.enums;

/**
 * @Description: 位置枚舉類
 * @Author: liming
 * @date 2020年01月16日
 */
public enum LocationEnum {
    CHANGSHA("changsha","長沙"),
    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;
    }
}

//這個類 是 長沙加盟商和廣東加盟商的父類,如果後續有其他的加盟商加進來,可以直接繼承這個類就好了

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

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

/**
 * @className: PissaAbstractFactory
 * @description: 抽象披薩工廠
 * @author: liming
 * @date: 2020/1/16
 **/
public abstract class PissaAbstractFactory {
    abstract Pissa create(String type);
}

長沙加盟商和廣東加盟商工廠如下:

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;
            //省略n個case
            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;
            //省略n個case
            default:
                p = new Pissa();
        }
        return p;
    }
}

原來的PissaFactory改成:

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


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

/**
 * @className: PissaFactory
 * @description: 簡單的披薩生產工廠
 * @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;
    }
}

ChangshaGreenPissa,ChangshaRedPissa,GuangzhouGreenPissa,GuangzhouRedPissa 這幾個類變化不大,貼一個類,其餘的差不多

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: 綠色披薩
 * @author: liming
 * @date: 2020/1/16
 **/
@Data
public class ChangshaGreenPissa extends  Pissa{

    public ChangshaGreenPissa() {
        this.colors = Arrays.asList(ColorEnum.GREEN.getDesc());
        this.name = "一個包含"+this.colors+"的披薩";
        this.price = 10.0;
    }

    @Override
    public String getDesc () {
        return this.name+",\t 價格:"+this.price+",\t 生產地點位於:" + ChangshaPissaFactory.LOCALTION;
        //這裏增加了生產位置
    }
}

那麼這麼一改造的話。後續來再多的加盟商都可以適配這個模式。

寫一個測試類試下:

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: 測試類
 * @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());
    }
}

這樣就能改最小的代碼,又可以適配不同的加盟商(產品)。

總結一下:簡單工廠模式和抽象工廠模式的區別

簡單工廠模式對於生成少量的對象來說有好處,但是沒有辦法做區分多產品(如果要在簡單工廠模式裏面區分產品也是可以的,只不過會帶來更多的if else

而且魯迅說過,太多的人修改同一個類的話,肯定會把別人的改錯,如果每一個加盟商只維護自己的那一部分功能,出錯的概率也會相對減少,影響面也不會擴散到其他的加盟商)

代碼已上傳github(github主頁:https://github.com/q920447939/java-study)
代碼地址:https://github.com/q920447939/java-study/tree/master/java-bases/src/main/java/cn/withme/pattern/abstractFactory

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章