模板方法模式
定義:在一個方法中定義一個算法的骨架,將一些處理的步驟延遲到子類去做處理,可以使在子類不改變算法結構的情況下, 重新定義算法的步驟。
設計院原則
好萊塢原則:別調用我們,我們會調用你。
先來看下簡單的代碼實現:
定義一個父類:果汁流程製作
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.策略模式和模板方法模式都封裝算法,一個用組合,一個用繼承