1. 程式人生 > >工廠模式-依賴倒置原則

工廠模式-依賴倒置原則

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

 1 package com.factoryPattern.factory;
2 3 /** 4 * @program: designPattern 5 * @description: 麵包口味的抽象類 6 * @author: Mr.Yang 7 * @create: 2018-11-18 19:24 8 **/ 9 public 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 }
View Code
 

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

 package com.factoryPattern.breadKind;
 
 import com.factoryPattern.breadKind.factory.BreadFactory;
 
 /**
  * @program: designPattern
  * @description: 奶油味麵包
  * @author: Mr.Yang
  * @create:
 **/
public class CreamBread extends BreadFactory {
    public CreamBread(){
        name="奶油味";
        type="2";
    }
    //可以重寫父類方法,進行特殊處理
}
View Code
 

蘋果味麵包

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

然後是銷售系統

 1  package com.factoryPattern.breadKind.breadOrder;
 2  
 3  import com.factoryPattern.breadKind.AppleBread;
 4  import com.factoryPattern.breadKind.CreamBread;
 5  import com.factoryPattern.breadKind.factory.BreadFactory;
 6  
 7  /**
 8   * @program: designPattern
 9   * @description: 麵包訂單銷售類
10  * @author: Mr.Yang
11  * @create:
12  **/
13 public 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 }
View Code
 

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

新增了一個工程類

 1  package com.factoryPattern.breadCreate;
 2  
 3  import com.factoryPattern.breadKind.AppleBread;
 4  import com.factoryPattern.breadKind.CreamBread;
 5  import com.factoryPattern.breadKind.factory.BreadFactory;
 6  
 7  /**
 8   * @program: designPattern
 9   * @description: 麵包建立工程
10  * @author: Mr.Yang
11  * @create:
12  **/
13 public 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 }
View Code

修改了銷售類

 1  package com.factoryPattern.breadKind.breadOrder;
 2  
 3  import com.factoryPattern.breadCreate.BreadCreateFactory;
 4  import com.factoryPattern.breadKind.factory.BreadFactory;
 5  
 6  /**
 7   * @program: designPattern
 8   * @description: 麵包訂單銷售類
 9   * @author: Mr.Yang
10  * @create:
11  **/
12 public 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 }
View Code
 

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

 1  package com.factoryPattern.breadStore;
 2  
 3  import com.factoryPattern.factory.BreadFactory;
 4  
 5  /**
 6   * @program: designPattern
 7   * @description: 麵包商店抽象類
 8   * @author: Mr.Yang
 9   * @create: -- :
10  **/
11 public 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 }
View Code
 

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

 1 package com.factoryPattern.breadStore;
 2  
 3  import com.factoryPattern.factory.BreadFactory;
 4  import com.factoryPattern.kind.ChinaAppleBread;
 5  import com.factoryPattern.kind.ChinaCreamBread;
 6  
 7  /**
 8   * @program: designPattern
 9   * @description: 中國店鋪子類
10  * @author: Mr.Yang
11  * @create: -- :
12  **/
13 public 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 }
View Code
 

建立一個新加坡店鋪子類

 1 package com.factoryPattern.breadStore;
 2  
 3  import com.factoryPattern.factory.BreadFactory;
 4  import com.factoryPattern.kind.SingaporeAppleBread;
 5  import com.factoryPattern.kind.SingaporeCreamBread;
 6  
 7  /**
 8   * @program: designPattern
 9   * @description: 新加坡店鋪子類
10  * @author: Mr.Yang
11  * @create: -- :
12  **/
13 public 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 }
View Code

 

 

建立一個泰國店鋪子類

 1  package com.factoryPattern.breadStore;
 2  
 3  import com.factoryPattern.factory.BreadFactory;
 4  import com.factoryPattern.kind.ThailandAppleBread;
 5  
 6  /**
 7   * @program: designPattern
 8   * @description: 泰國店鋪子類
 9   * @author: Mr.Yang
10  * @create: -- :
11  **/
12 public 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 }
View Code

 

 

麵包口味的抽象類

 1  package com.factoryPattern.factory;
 2  
 3  /**
 4   * @program: designPattern
 5   * @description: 麵包口味的抽象類
 6   * @author: Mr.Yang
 7   * @create: -- :
 8   **/
 9  public 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 }
View Code

 

 

中國蘋果口味麵包

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

中國奶油口味麵包

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

 

 

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

測試類

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

 

 

測試結果

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

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

 

 

阿三:大致如圖,工程模式的定義:定義了一個建立物件的介面,但有子類決定要例項化的類是哪一個。工程方法讓類把例項化推遲到子類

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

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