設計模式 - 工廠模式-依賴倒置原則

老闆:阿飛啊,我們公司最近接了個項目,你看着設計一下,我給你說下需求。
項目組長阿飛:好啊,什麼需求?
老闆:我們找了一個合作的商鋪,他們要設計一套麪包銷售系統。主要功能,根據用戶選擇的麪包種類來下訂單,麪包目前有奶油口味麪包和蘋果口味麪包,所有面包的製作流程都是---攪拌,搓圓,加工,烘烤。
項目組長阿飛:好的,我去想想怎麼設計。
項目組長阿飛:小三啊,我給你個任務,…………,聽懂了嗎?
阿三:聽懂了,飛哥。
項目組長阿飛:嗯嗯,好的,這個任務就交給你了,我要去處理點事情,我相信你。
阿三:。。。
三天過後。
阿三:飛哥,設計好了,你看下。

 1package com.factoryPattern.breadKind.factory;
 2
 3/**
 4 * @program: designPattern
 5 * @description: 麪包口味的抽象類
 6 * @author: Mr.Yang
 7 * @create: 2018-11-18 19:24
 8 **/
 9public abstract class BreadFactory {
10    protected String name;
11    protected String type;
12
13    public BreadFactory stir(){
14        System.out.println("攪拌");
15        return this;
16    }
17
18    public BreadFactory rubbingRound(){
19        System.out.println("搓圓");
20        return this;
21    }
22
23    public BreadFactory machining(){
24        System.out.println("加工");
25        return this;
26    }
27    public BreadFactory bake(){
28        System.out.println("烘烤");
29        return this;
30    }
31
32    public String getName() {
33        return name;
34    }
35
36    public BreadFactory setName(String name) {
37        this.name = name;
38        return this;
39    }
40
41    public String getType() {
42        return type;
43    }
44
45    public BreadFactory setType(String type) {
46        this.type = type;
47        return this;
48    }
49}

現在已有的兩種口味繼承這個抽象類--奶油麪包

 1package com.factoryPattern.breadKind;
 2
 3import com.factoryPattern.breadKind.factory.BreadFactory;
 4
 5/**
 6 * @program: designPattern
 7 * @description: 奶油味麪包
 8 * @author: Mr.Yang
 9 * @create: 2018-11-18 19:24
10 **/
11public class CreamBread extends BreadFactory {
12    public CreamBread(){
13        name="奶油味";
14        type="2";
15    }
16    //可以重寫父類方法,進行特殊處理
17}

蘋果味麪包

 1package com.factoryPattern.breadKind;
 2
 3import com.factoryPattern.breadKind.factory.BreadFactory;
 4
 5/**
 6 * @program: designPattern
 7 * @description: 蘋果味麪包
 8 * @author: Mr.Yang
 9 * @create: 2018-11-18 19:25
10 **/
11public class AppleBread extends BreadFactory {
12    public AppleBread(){
13        name="蘋果味";
14        type="1";
15    }
16    //可以重寫父類方法,進行特殊處理
17}

然後是銷售系統

 1package com.factoryPattern.breadKind.breadOrder;
 2
 3import com.factoryPattern.breadKind.AppleBread;
 4import com.factoryPattern.breadKind.CreamBread;
 5import com.factoryPattern.breadKind.factory.BreadFactory;
 6
 7/**
 8 * @program: designPattern
 9 * @description: 麪包訂單銷售類
10 * @author: Mr.Yang
11 * @create: 2018-11-18 19:26
12 **/
13public class BreadOrder {
14
15
16    BreadFactory orderBread(String type){
17        BreadFactory breadFactory;
18        if("cream".equalsIgnoreCase(type)){
19            System.out.println("創建奶油口味麪包");
20            breadFactory=new CreamBread();
21        }else if("apple".equalsIgnoreCase(type)){
22            System.out.println("創建蘋果口味麪包");
23            breadFactory=new AppleBread();
24        }else{
25            System.out.println("無法確認的麪包類型");
26            return null;
27        }
28
29        return breadFactory.stir()
30                .rubbingRound()
31                .machining()
32                .bake();
33    }
34}

項目組長阿飛:三啊,不錯,學會使用抽象了,但是如果我還要增加好幾種麪包類型呢?阿爾法麪包銷售不好,不想做這個了呢?之前給你說過設計模式的原則之一,對拓展開放,對修改關閉。如果有改動,可能會一直在這個代碼的基礎上累加做修改的。最好把創建對象的代碼與銷售的代碼分隔開。 
阿三:好的,我再修改修改(真的是,搞這麼麻煩幹嘛!)
又三天過後。
阿三:飛哥,修改好了,你看下。

新增了一個工程類

 1package com.factoryPattern.breadCreate;
 2
 3import com.factoryPattern.breadKind.AppleBread;
 4import com.factoryPattern.breadKind.CreamBread;
 5import com.factoryPattern.breadKind.factory.BreadFactory;
 6
 7/**
 8 * @program: designPattern
 9 * @description: 麪包創建工程
10 * @author: Mr.Yang
11 * @create: 2018-11-18 19:37
12 **/
13public class BreadCreateFactory {
14    public BreadFactory createBread(String type){
15        BreadFactory breadFactory=null;
16        if("cream".equalsIgnoreCase(type)){
17            System.out.println("創建奶油口味麪包");
18            breadFactory=new CreamBread();
19        }else if("apple".equalsIgnoreCase(type)){
20            System.out.println("創建蘋果口味麪包");
21            breadFactory=new AppleBread();
22        }else{
23            System.out.println("無法確認的麪包類型");
24            return null;
25        }
26        return breadFactory;
27    }
28}

修改了銷售類

 1package com.factoryPattern.breadKind.breadOrder;
 2
 3import com.factoryPattern.breadCreate.BreadCreateFactory;
 4import com.factoryPattern.breadKind.factory.BreadFactory;
 5
 6/**
 7 * @program: designPattern
 8 * @description: 麪包訂單銷售類
 9 * @author: Mr.Yang
10 * @create: 2018-11-18 19:26
11 **/
12public class BreadOrder {
13    BreadCreateFactory breadCreateFactory;
14
15    public BreadOrder(BreadCreateFactory breadCreateFactory) {
16        this.breadCreateFactory = breadCreateFactory;
17    }
18
19    BreadFactory orderBread(String type) {
20        return breadCreateFactory.createBread(type)
21                .stir()
22                .rubbingRound()
23                .machining()
24                .bake();
25    }
26}

項目組長阿飛:不錯,這是一個簡單工廠,但是你要記住,這並不是一個設計模式,而是一個編程習慣,一個不錯的編程習慣,簡單工廠把全部的事情,在一個地方處理完了,工廠方法是創建一個框架,讓子類決定如何實現。還有領導說需求變了,這個麪包店開了分店,一個在泰國,一個在新加坡,你看着再修改下吧,你可以考慮加入工廠方法。 
阿三:好的(我服了,真的是****)
又三天過後。
阿三:飛哥,修改好了,這是完整代碼,你看下。
先是一個麪包商店抽象類

 1package com.factoryPattern.breadStore;
 2
 3import com.factoryPattern.factory.BreadFactory;
 4
 5/**
 6 * @program: designPattern
 7 * @description: 麪包商店抽象類
 8 * @author: Mr.Yang
 9 * @create: 2018-11-18 19:51
10 **/
11public abstract class BreadStoreFactory {
12
13    public BreadFactory orderBread(String type) {
14        return createBread(type)
15                .stir()
16                .rubbingRound()
17                .machining()
18                .bake();
19    }
20
21    abstract BreadFactory createBread(String type);
22}

創建一箇中國店鋪子類實現商店抽象類

 1package com.factoryPattern.breadStore;
 2
 3import com.factoryPattern.factory.BreadFactory;
 4import com.factoryPattern.kind.ChinaAppleBread;
 5import com.factoryPattern.kind.ChinaCreamBread;
 6
 7/**
 8 * @program: designPattern
 9 * @description: 中國店鋪子類
10 * @author: Mr.Yang
11 * @create: 2018-11-18 19:55
12 **/
13public class ChinaStore extends BreadStoreFactory{
14    @Override
15    BreadFactory createBread(String type) {
16        BreadFactory breadFactory=null;
17        if("cream".equalsIgnoreCase(type)){
18            System.out.println("創建中國奶油口味麪包");
19            breadFactory=new ChinaCreamBread();
20        }else if("apple".equalsIgnoreCase(type)){
21            System.out.println("創建中國蘋果口味麪包");
22            breadFactory=new ChinaAppleBread();
23        }else{
24            System.out.println("無法確認的麪包類型");
25            return null;
26        }
27        return breadFactory;
28    }
29}

創建一個新加坡店鋪子類

 1package com.factoryPattern.breadStore;
 2
 3import com.factoryPattern.factory.BreadFactory;
 4import com.factoryPattern.kind.SingaporeAppleBread;
 5import com.factoryPattern.kind.SingaporeCreamBread;
 6
 7/**
 8 * @program: designPattern
 9 * @description: 新加坡店鋪子類
10 * @author: Mr.Yang
11 * @create: 2018-11-18 19:56
12 **/
13public class SingaporeStore extends BreadStoreFactory {
14    @Override
15    BreadFactory createBread(String type) {
16        BreadFactory breadFactory=null;
17        if("cream".equalsIgnoreCase(type)){
18            System.out.println("創建新加坡奶油口味麪包");
19            breadFactory=new SingaporeCreamBread();
20        }else if("apple".equalsIgnoreCase(type)){
21            System.out.println("創建新加坡蘋果口味麪包");
22            breadFactory=new SingaporeAppleBread();
23        }else{
24            System.out.println("無法確認的麪包類型");
25            return null;
26        }
27        return breadFactory;
28    }
29}

創建一個泰國店鋪子類

 1package com.factoryPattern.breadStore;
 2
 3import com.factoryPattern.factory.BreadFactory;
 4import com.factoryPattern.kind.ThailandAppleBread;
 5
 6/**
 7 * @program: designPattern
 8 * @description: 泰國店鋪子類
 9 * @author: Mr.Yang
10 * @create: 2018-11-18 19:56
11 **/
12public class ThailandStore extends BreadStoreFactory {
13    @Override
14    BreadFactory createBread(String type) {
15        BreadFactory breadFactory=null;
16        if("cream".equalsIgnoreCase(type)){
17            System.out.println("創建泰國奶油口味麪包");
18            breadFactory=new ThailandAppleBread();
19        }else if("apple".equalsIgnoreCase(type)){
20            System.out.println("創建泰國蘋果口味麪包");
21            breadFactory=new ThailandAppleBread();
22        }else{
23            System.out.println("無法確認的麪包類型");
24            return null;
25        }
26        return breadFactory;
27    }
28}

麪包口味的抽象類

 1package com.factoryPattern.factory;
 2
 3/**
 4 * @program: designPattern
 5 * @description: 麪包口味的抽象類
 6 * @author: Mr.Yang
 7 * @create: 2018-11-18 19:24
 8 **/
 9public abstract class BreadFactory {
10    protected String name;
11    protected String type;
12
13    public BreadFactory stir(){
14        System.out.println("攪拌");
15        return this;
16    }
17
18    public BreadFactory rubbingRound(){
19        System.out.println("搓圓");
20        return this;
21    }
22
23    public BreadFactory machining(){
24        System.out.println("加工");
25        return this;
26    }
27    public BreadFactory bake(){
28        System.out.println("烘烤");
29        return this;
30    }
31
32    public String getName() {
33        return name;
34    }
35
36    public BreadFactory setName(String name) {
37        this.name = name;
38        return this;
39    }
40
41    public String getType() {
42        return type;
43    }
44
45    public BreadFactory setType(String type) {
46        this.type = type;
47        return this;
48    }
49}

中國蘋果口味麪包

 1package com.factoryPattern.kind;
 2
 3import com.factoryPattern.factory.BreadFactory;
 4
 5/**
 6 * @program: designPattern
 7 * @description: 中國蘋果口味麪包
 8 * @author: Mr.Yang
 9 * @create: 2018-11-18 19:48
10 **/
11public class ChinaAppleBread  extends BreadFactory {
12    public ChinaAppleBread(){
13        name="中國蘋果口味";
14        type="1";
15    }
16    //可以重寫父類方法,進行特殊處理
17}

中國奶油口味麪包

 1package com.factoryPattern.kind;
 2
 3import com.factoryPattern.factory.BreadFactory;
 4
 5/**
 6 * @program: designPattern
 7 * @description: 中國奶油口味麪包
 8 * @author: Mr.Yang
 9 * @create: 2018-11-18 19:48
10 **/
11public class ChinaCreamBread extends BreadFactory {
12    public ChinaCreamBread(){
13        name="中國奶油口味";
14        type="2";
15    }
16    //可以重寫父類方法,進行特殊處理
17}

還有新加坡蘋果口味麪包,新加坡奶油口味麪包,泰國蘋果口味麪包,泰國奶油口味麪包

測試類

 1package com.factoryPattern.patternTest;
 2
 3import com.factoryPattern.breadStore.BreadStoreFactory;
 4import com.factoryPattern.breadStore.ChinaStore;
 5
 6/**
 7 * @program: designPattern
 8 * @description: 測試類
 9 * @author: Mr.Yang
10 * @create: 2018-11-18 20:13
11 **/
12public class Test {
13    public static void main(String[] args) {
14        System.out.println("中國顧客買蘋果味道麪包");
15        BreadStoreFactory chinaBreadStoreFactory = new ChinaStore();
16        chinaBreadStoreFactory.orderBread("apple");
17    }
18}

測試結果

1中國顧客買蘋果味道麪包
2創建中國蘋果口味麪包
3攪拌
4搓圓
5加工
6烘烤

項目組長阿飛:看着不錯,給我講解一下吧。
阿三:我所用的是設計模式中的工廠模式,讓子類決定該創建的對象是什麼,來達到將對象創建的過程封裝的目的。我簡單的畫了個圖

 

 

阿三:大致如圖,工程模式的定義:定義了一個創建對象的接口,但有子類決定要實例化的類是哪一個。工程方法讓類把實例化推遲到子類

項目組長阿飛:很好,看來你已經掌握了工程模式的精髓,工程模式遵循了一個設計原則:“要依賴抽象,不要依賴具體實現。”,它有一個響亮的名字:“依賴倒置原則”。 你看你這兩個圖。創建者抽象BreadStoreFactory依賴與BreadFactory抽象類,麪包的具體實現(chinaAppleBread,chinaCreamBread)依賴與BreadFactory抽象類,想要遵循依賴倒置原則,工程方法並非是唯一的,但是確是最有威力的技巧之一。

阿三:好的(我早就知道了---膨脹的一批)

 

JAVA知識分享總結

掃描二維碼關注微信公衆號!

 

 

Gatiln

掃描二維碼加我微信好友!

 

知識分享羣

掃描二維碼進微信交流羣!

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