設計模式 - 框架創建中常見設計模式-模板方法模式

模板方法模式
定義:在一個方法中定義一個算法的骨架,將一些處理的步驟延遲到子類去做處理,可以使在子類不改變算法結構的情況下, 重新定義算法的步驟。

設計院原則

好萊塢原則:別調用我們,我們會調用你。

先來看下簡單的代碼實現:

定義一個父類:果汁流程製作

 1package com.templateModePattern.parentClass;
 2
 3/**
 4 * @program: test
 5 * @description: 果汁的製造簡單流程:--》清洗水果 --》放入修飾材料--》放入榨汁機中
 6 *               因爲放入修飾材料的流程,各個果汁不一樣,所以放入子類去實現
 7 * @author: Mr.Yang
 8 * @create: 2018-12-22 13:19
 9 **/
10public  abstract  class FruitJuiceParent {
11
12    /**
13     * 果汁的製造流程(當作固定流程,不會變),這個方法不希望子類去覆蓋,
14     *子類只需要實現putMaterial()方法就行,聲明爲final,骨架方法
15     */
16    public  final void makeFruitJuice(){
17        cleanIts();
18        putMaterial();
19        putMachine();
20    }
21
22    protected  abstract void putMaterial();
23
24    /**
25     * 清洗水果
26     */
27    protected  void cleanIts(){
28        System.out.println("clean fruit");
29    }
30
31    /**
32     * 放入榨汁機中
33     */
34    protected  void putMachine(){
35        System.out.println("put machine");
36    }
37}

子類蘋果汁,實現父類未實現的方法

 1package com.templateModePattern.subClass;
 2
 3import com.templateModePattern.parentClass.FruitJuiceParent;
 4
 5/**
 6 * @program: test
 7 * @description: 蘋果汁
 8 * @author: Mr.Yang
 9 * @create: 2018-12-22 13:26
10 **/
11public class AppleFruitJuice extends FruitJuiceParent {
12
13    /**
14     * 在蘋果汁放入蜂蜜,味道更好
15     */
16    public void putMaterial() {
17        System.out.println("Put in honey");
18    }
19
20}

子類西瓜汁,實現父類未實現的方法

 1package com.templateModePattern.subClass;
 2
 3import com.templateModePattern.parentClass.FruitJuiceParent;
 4
 5/**
 6 * @program: test
 7 * @description: 西瓜汁
 8 * @author: Mr.Yang
 9 * @create: 2018-12-22 13:29
10 **/
11public class WatermelonFruitJuice extends FruitJuiceParent {
12
13    /**
14     * 放入牛奶,味道更好
15     */
16    public void putMaterial() {
17        System.out.println("put in milk");
18    }
19}

掛鉤

鉤子是一種被聲明在抽象類中的方法,但只有空的或者默認實現,鉤子的存在,可以讓子類有能力對算法的不同點進行掛鉤,要不要掛鉤,由子類自行決定。

在方法中加入掛鉤代碼實現

父類加入判斷,如果true,去執行,讓子類去具體實現該方法,做處理

 1package com.templateModePattern.parentClass;
 2
 3/**
 4 * @program: test
 5 * @description: 果汁的製造簡單流程:--》清洗水果 --》放入修飾材料--》放入榨汁機中
 6 *               因爲放入修飾材料的流程,各個果汁不一樣,所以放入子類去實現
 7 * @author: Mr.Yang
 8 * @create: 2018-12-22 13:19
 9 **/
10public  abstract  class FruitJuiceParent {
11
12    /**
13     * 果汁的製造流程(當作固定流程,不會變),這個方法不希望子類去覆蓋,
14     * 子類只需要實現putMaterial()方法就行,聲明爲final
15     */
16    public final void makeFruitJuice(){
17        cleanIts();
18        if(isPutMaterIal()){
19            putMaterial();
20        }
21        putMachine();
22    }
23
24    protected abstract void putMaterial();
25
26    /**
27     * 清洗水果
28     */
29    protected void cleanIts(){
30        System.out.println("clean fruit");
31    }
32
33    /**
34     * 放入榨汁機中
35     */
36    protected void putMachine(){
37        System.out.println("put machine");
38    }
39
40    /**
41     * 父類增加判斷
42     * @return
43     */
44    protected boolean isPutMaterIal(){
45        return true;
46    }
47}

蘋果汁子類讓用戶去做選擇

 1package com.templateModePattern.subClass;
 2
 3import com.templateModePattern.parentClass.FruitJuiceParent;
 4import org.apache.commons.lang3.StringUtils;
 5
 6import java.io.BufferedReader;
 7import java.io.IOException;
 8import java.io.InputStreamReader;
 9
10/**
11 * @program: test
12 * @description: 蘋果汁
13 * @author: Mr.Yang
14 * @create: 2018-12-22 13:26
15 **/
16public class AppleFruitJuice extends FruitJuiceParent {
17
18    /**
19     * 在蘋果汁放入蜂蜜,味道更好
20     */
21    public void putMaterial() {
22        System.out.println("Put in honey");
23    }
24
25    /**
26     * 在子類覆蓋它,讓用戶去選擇
27     * @return
28     */
29    @Override
30    protected boolean isPutMaterIal() {
31        String userInput = getUserInput();
32        if(userInput.toLowerCase().startsWith("y")){
33            return true;
34        }else{
35            return false;
36        }
37    }
38
39    /**
40     * 得到用戶輸入的內容
41     * @return
42     */
43    private String getUserInput(){
44        String readString=null;
45        System.out.println("Do you want honey(y/n)?");
46        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
47        try {
48            readString = br.readLine();
49        } catch (IOException e) {
50            System.out.println("---異常---"+e);
51        }
52        if(StringUtils.isEmpty(readString)){
53            return "N";
54        }else{
55            return readString;
56        }
57    }
58}

西瓜汁子類讓用戶去做選擇

 1package com.templateModePattern.subClass;
 2
 3import com.templateModePattern.parentClass.FruitJuiceParent;
 4import org.apache.commons.lang3.StringUtils;
 5
 6import java.io.BufferedReader;
 7import java.io.IOException;
 8import java.io.InputStreamReader;
 9
10/**
11 * @program: test
12 * @description: 西瓜汁
13 * @author: Mr.Yang
14 * @create: 2018-12-22 13:29
15 **/
16public class WatermelonFruitJuice extends FruitJuiceParent {
17
18    /**
19     * 放入牛奶,味道更好
20     */
21    public void putMaterial() {
22        System.out.println("put in milk");
23    }
24
25
26    /**
27     * 在子類覆蓋它,讓用戶去選擇
28     * @return
29     */
30    @Override
31    protected boolean isPutMaterIal() {
32        String userInput = getUserInput();
33        if(userInput.toLowerCase().startsWith("y")){
34            return true;
35        }else{
36            return false;
37        }
38    }
39
40    /**
41     * 得到用戶輸入的內容
42     * @return
43     */
44    private String getUserInput(){
45        String readString=null;
46        System.out.println("Do you want milk(y/n)?");
47        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
48        try {
49            readString = br.readLine();
50        } catch (IOException e) {
51            System.out.println("---異常---"+e);
52        }
53        if(StringUtils.isEmpty(readString)){
54            return "N";
55        }else{
56            return readString;
57        }
58    }
59}

製造無添加草莓汁

 1package com.templateModePattern.subClass;
 2
 3import com.templateModePattern.parentClass.FruitJuiceParent;
 4
 5/**
 6 * @program: test
 7 * @description: 草莓汁,無添加
 8 * @author: Mr.Yang
 9 * @create: 2018-12-22 13:46
10 **/
11public class StrawberryFruitJuice extends FruitJuiceParent {
12
13    protected void putMaterial() {
14
15    }
16
17    @Override
18    protected boolean isPutMaterIal() {
19        return false;
20    }
21}

測試結果:

 1____________蘋果汁製作開始____________
 2clean fruit
 3Do you want honey(y/n)?
 4y
 5Put in honey
 6put machine
 7____________蘋果汁製作結束____________
 8
 9
10____________草莓汁製作開始____________
11clean fruit
12put machine
13____________草莓汁製作結束____________
14
15
16____________西瓜汁製作____________
17clean fruit
18Do you want milk(y/n)?
19n
20put machine
21____________西瓜汁結束____________

好萊塢原則與依賴倒置原則的區別

依賴倒置提倡避免使用具體類,多使用抽象。
好萊塢原則是用在創建框架或組件上的一種技巧,讓底層組件能夠被掛鉤計算中,又不會讓高層組件依賴低層組件。

重點內容與比較

1.模板方法定義了算法的步驟,將步驟的實例延遲到子類
2.提供了一種代碼複用的技巧
3.鉤子的瞭解與使用
4.好萊塢原則提倡將決策權放到高層(父類)
5.策略模式和模板方法模式都封裝算法,一個用組合,一個用繼承

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