行为模式---之--模板方法模式
模板方法模式是类的行为模式,准备一个抽象类,将部分逻辑以具体方法以及具体构造子的形式实现,然后声明一些抽象方法来迫使子类实现剩余逻辑。不同的子类可以以不同的方式实现这些抽象方法,从而对剩余的逻辑有不同的实现。这就是模板方法的用意。
模板方法模式是基于继承的代码复用技术,模版方法模式的结构和用法也是面向对象设计的核心。
模板方法模式是基于继承的代码复用技术,模版方法模式的结构和用法也是面向对象设计的核心。
它涉及两个角色:
1.抽象模版(Abstract Template)角色有如下责任
定义一个或多个抽象操作,以便让子类实现。这些抽象操作叫做基本操作,它们是一个顶级逻辑的组成步骤
定义并实现了一个模板方法。这个模板方法一般是一个具体方法,它给出了一个顶级逻辑的骨架,而逻辑的组成步骤在相应的抽象操作中,推迟到子类实现。顶级逻辑也有可能调用一些具体方法
2.具体模版(Concrete Template)角色有如下责任:
实现父类所定义的一个或多个抽象方法,它们是一个顶级逻辑的组成步骤
每一个抽象模板角色都可以有任意多个具体模板角色与之对应,而每一个具体模板角色都可以给出这些抽象方法(也就是顶级逻辑的组成步骤)的不同实现,从而使得顶级逻辑的实现各不相同。
模板方法鼓励恰当地使用继承,此模式可以用来改写一些拥有相同功能的相关的类,将可复用的一般性的行为代码移到基类里面,而把特殊化的行为代码移到子类里面。
示例代码:
1 public class TemplateMethodTest { 2 public static void main(String[] args) { 3 AbstractClass ac = new ConcreteClass(); 4 ac.TemplateMethod(); 5 } 6 } 7 //抽象模板类 8 abstract class AbstractClass{ 9 //模版方法的声明和实现 10 public void TemplateMethod(){ 11 //调用基本方法(由子类实现) 12 doOperation1(); 13 doOperation2(); 14 doOperation3(); 15 } 16 //基本方法声明(由子类实现) 17 protected abstract void doOperation1(); 18 protected abstract void doOperation2(); 19 protected abstract void doOperation3(); 20 } 21 22 //具体模版类 23 class ConcreteClass extends AbstractClass{ 24 25 @Override 26 protected void doOperation1() { 27 System.out.println("Do one"); 28 } 29 30 @Override 31 protected void doOperation2() { 32 System.out.println("Do two"); 33 } 34 35 @Override 36 protected void doOperation3() { 37 System.out.println("Do three"); 38 } 39 40 }
模板方法中的方法:
1.模版方法:一个模板方法是定义在抽象类中的,把基本操作方法组合在一起形成一个总算法或一个总行为的方法。这个模板方法一般会在抽象类中定义,并由子类不加以修改地完全继承下来。
一个抽象类可以有任意多个模版方法,而不限于一个。每一个模版方法都可以调用 任意多个具体方法。
2.基本方法:又分为三种
2.1抽象方法:一个抽象方法由抽象类声明,由具体子类实现
2.2具体方法:一个具体方法由抽象类声明并实现,而子类并不实现或置换。有些具体方法可以起到工厂方法的作用,这样的具体方法又叫做工厂方法。
2.3.钩子方法:一个钩子方法由抽象类声明并实现,而子类会加以扩展。通常抽象类给出的实现是一个空实现,作为方法的默认实现。钩子方法的名字应当以do开始,这是熟悉设计模式的Java程序设计师的标准做法。在HttpServlet里面,基本方法也遵从这一命名规则
模版方法与重构及设计:
在对一个继承的等级结构做重构时,一个应当遵从的原则是将行为尽量移动到结构的顶端,而将状态尽量移动到结构的低端。
1.应当根据行为而不是状态定义一个类。也就是说,一个类的实现首先建立在行为的基础上,而不是建立在状态的基础之上
2.在实现行为时,是用抽象状态而不是具体状态。如果一个行为涉及到对象的状态时,使用间接的引用而不是直接的引用。就是,应当使用取值方法而不是直接引用属性
3.给操作划分层次,一个类的行为应当放到一个小组核心方法里面,这些方法可以很方便地在子类中加以置换
4.将状态属性的确认推迟到子类中,不要在抽象类中过早声明属性变量,应将它们尽量推迟到子类中去声明。在抽象超类中,如果需要状态属性的话,可以调用抽象的取值方法,而将抽象的取值方法的实现放到具体子类中。
如果能遵从这样的原则,那么就可以在等级结构中将接口与实现分隔开来,将抽象与具体分割开来,从而保证代码可以最大限度地被复用。