模板方法模式

1,模板方法的定义
          
定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤
 
  uml
     模板方法模式
 
  
  •  AbstractClass:抽象类。用来定义算法骨架和原语操作,具体的子类通过重定义这些原语操作来实现一个算法的各个步骤。在这个类里面,还可以提供算法中通用实现。

  • ConcreteClass:具体实现类。用来实现算法骨架中的某些步骤,完成与特定子类相关的功能

    示例代码
     1 public abstract class AbstractClass {
     2     /**
     3      * 原语操作1,所谓原语操作就是抽象的操作,必须要由子类提供实现
     4      */
     5     public abstract void doPrimitiveOperation1();
     6     public abstract void doPrimitiveOperation2();
     7     
     8     public final void templateMethod(){
     9         doPrimitiveOperation1();
    10         doPrimitiveOperation2();
    11     }
    12     
    13 }
     1 public class ConcreteClasee extends AbstractClass {
     2 
     3     @Override
     4     public void doPrimitiveOperation1() {
     5         
     6     }
     7 
     8     @Override
     9     public void doPrimitiveOperation2() {
    10         
    11     }
    12 
    13 }
2,模板方法模式的功能
模板方法模式的功能在于固定算法骨架,而让具体算法实现可扩展      


3,变与不变
  • 程序设计的一个重要的思考点就是“变与不变”,也就是分析程序中哪些功能是可变的,哪些功能是不变的,然后把不变的部分抽象出来,进行公共的实现,把变化的部分分离出去,用接口来封装隔离,或者是抽象类约束子类行为。  

4,模板的写法
     通常在模板里面包含以下操作类型。
  • 模板方法:就是定义算法骨架的方法。

  • 具体的操作:在模板中直接实现某些步骤的方法。通常这些步骤的实现算法是固定的,而且是不怎么变的
    因此可以将其当做公共功能实现在模板中。

  •  具体的AbstractClass操作:在模板中实现某些公共功能,可以提供子类使用,一般不是具体的算法步骤
    的实心,而是一些辅助公共功能。

  • 原语操作: 就是模板中定义的抽象操作,通常是模板方法需要调用的操作,是必须的操作,而且在父类中还没有办法确定下来如何实现,需要子类来真正实现的方法。

  • 钩子操作:在模板中定义,并提供默认实现的操作

  • Factory Method:在模板方法中,如果需要得到某些对象实例的话,可以考虑通过工厂方法模式来获取
    把具体的构建对象的实现延迟到子类中去。
 

    示例代码
    

 1 public abstract class AbstractTemplate {
 2     
 3     /**
 4      * 模板方法,定义算法骨架
 5      */
 6     public final void templateMethod() {
 7         this.operation1();
 8         this.operation2();
 9         
10         this.doPrimitiveOperation1();
11         this.doPrimitiveOperation2();
12         
13         this.hookOperation1();
14     }
15     
16     /**
17      * 具体操作1,算法中的步骤,固定实现,而且子类不需要访问
18      */
19     private void operation1() {
20         //TODO
21     }
22     
23     /**
24      * 具体操作2,算法中的步骤,固定实现,子类可能需要访问
25      * 当然也可以定义成protected的,不可以被覆盖,因此是final的
26      */
27     protected final void operation2(){
28         //TODO
29     }
30     
31     /**
32      * 具体的AbstractClass操作,子类的公共功能
33      * 但通常不是具体的算法步骤
34      */
35     protected void commonOperation() {
36         //TODO
37     }
38     
39     /**
40      * 原语操作1,算法中的必要步骤,父类无法确定如何真正实现,需要子类来实现
41      */
42     protected abstract void doPrimitiveOperation1();
43     
44     protected abstract void doPrimitiveOperation2();
45     
46     /**
47      * 钩子操作,算法中的步骤,不一定需要,提供默认实现
48      * 由子类选择并具体实现
49      */
50     protected void hookOperation1(){
51         //TODO
52     }
53     
54     /**
55      * 工厂方法,创建某个对象,这里用Object代替了,在算法中实现可能需要
56      * @return
57      */
58     protected abstract Object createOneObject();
59 
60 }

5,模板方法模式的优缺点
 
  • 模板方法的优点事实现代码复用。
    模板方法模式是一种实现代码复用的很好的手段。通过把子类的公共功能提炼和抽取把公共部分放到模板中去实现。

  • 模板方法模式的缺点是算法骨架不容易升级。
    模板方法最基本的功能就是通过模板的制定,把算法骨架完全固定下来。
    事实上模板和子类是非常耦合的,如果要对模板中的算法骨架进行变更,科恩给你就会要求所有相关的子类进行相应的变化。所以抽取算法骨架的时候要特别小心,尽量确保是不会变化的部分才放倒模板中。
 



6,模板方法模式的本质

           模板方法模式的本质:固定算法骨架





7,何时选用模板方法模式
 
  • 需要固定定义算法骨架,实现一个算法的不变部分,并把可变的行为留给子类来实现的情况
  • 各个子类中具有公共行为,应该抽取出来,集中在一个公共类中去实现,从而避免代码重复
  • 需要控制子类扩展的情况。模板方法模式会在特定的点来调用子类的方法,这样只允许在这些点进行扩展