框架创建中常见设计模式-模板方法模式

模板方法模式
定义:在一个方法中定义一个算法的骨架,将一些处理的步骤延迟到子类去做处理,可以使在子类不改变算法结构的情况下, 重新定义算法的步骤。

设计院原则

好莱坞原则:别调用我们,我们会调用你。

先来看下简单的代码实现:

定义一个父类:果汁流程制作

 1 package com.templateModePattern.parentClass;
 2 
 3 /**
 4  * @program: test
 5  * @description: 果汁的制造简单流程:--》清洗水果 --》放入修饰材料--》放入榨汁机中
 6  *               因为放入修饰材料的流程,各个果汁不一样,所以放入子类去实现
 7  * @author: Mr.Yang
 8  * @create: 2018-12-22 13:19
 9  **/
10 public  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 }
 

子类苹果汁,实现父类未实现的方法

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

子类西瓜汁,实现父类未实现的方法

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

挂钩

钩子是一种被声明在抽象类中的方法,但只有空的或者默认实现,钩子的存在,可以让子类有能力对算法的不同点进行挂钩,要不要挂钩,由子类自行决定。

在方法中加入挂钩代码实现

父类加入判断,如果true,去执行,让子类去具体实现该方法,做处理

 1 package com.templateModePattern.parentClass;
 2 
 3 /**
 4  * @program: test
 5  * @description: 果汁的制造简单流程:--》清洗水果 --》放入修饰材料--》放入榨汁机中
 6  *               因为放入修饰材料的流程,各个果汁不一样,所以放入子类去实现
 7  * @author: Mr.Yang
 8  * @create: 2018-12-22 13:19
 9  **/
10 public  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 }
 

苹果汁子类让用户去做选择

 1 package com.templateModePattern.subClass;
 2 
 3 import com.templateModePattern.parentClass.FruitJuiceParent;
 4 import org.apache.commons.lang3.StringUtils;
 5 
 6 import java.io.BufferedReader;
 7 import java.io.IOException;
 8 import java.io.InputStreamReader;
 9 
10 /**
11  * @program: test
12  * @description: 苹果汁
13  * @author: Mr.Yang
14  * @create: 2018-12-22 13:26
15  **/
16 public 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 }
 

西瓜汁子类让用户去做选择

 1 package com.templateModePattern.subClass;
 2 
 3 import com.templateModePattern.parentClass.FruitJuiceParent;
 4 import org.apache.commons.lang3.StringUtils;
 5 
 6 import java.io.BufferedReader;
 7 import java.io.IOException;
 8 import java.io.InputStreamReader;
 9 
10 /**
11  * @program: test
12  * @description: 西瓜汁
13  * @author: Mr.Yang
14  * @create: 2018-12-22 13:29
15  **/
16 public 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 }
 

制造无添加草莓汁

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

测试结果:

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

好莱坞原则与依赖倒置原则的区别

依赖倒置提倡避免使用具体类,多使用抽象。
好莱坞原则是用在创建框架或组件上的一种技巧,让底层组件能够被挂钩计算中,又不会让高层组件依赖低层组件。

重点内容与比较

1.模板方法定义了算法的步骤,将步骤的实例延迟到子类
2.提供了一种代码复用的技巧
3.钩子的了解与使用
4.好莱坞原则提倡将决策权放到高层(父类)
5.策略模式和模板方法模式都封装算法,一个用组合,一个用继承

猜你喜欢

转载自www.cnblogs.com/yangxiaojie/p/10161048.html