模板方法模式(TemplateMethod)
当我们要完成在某一细节层次一致的一个过程或一系列步骤在更详细的层次上的实现可能不同时,我们考虑用模板方法模式来处理。
模板方法模式,定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
总的来说,模板模式就是通过抽象类来定义一个逻辑模板,逻辑框架、逻辑原型,然后将无法决定的部分抽象成抽象类交由子类来实现,一般这些抽象类的调用逻辑还是在抽象类中完成,也就是说,算法的结构是被模板定义的。这么看来,模板就是定义一个框架,比如盖房子,我们定义一个模板:房子要封闭,有门,有窗等等,但是要什么样的门,什么样的窗,这些并不在模板中描述,这个交给子类来完善,比如门使用防盗门,窗使用北向的窗等等。
其中基本方法一般会用final修饰,保证其不会被子类修改,而模板方法则使用protected修饰,表明其需要在子类中实现。
其实,模板模式中还有一个钩子方法的概念,有人称,具有钩子方法的模板模式才算完整,也许吧。
钩子方法时干啥的呢?钩子就是给子类一个授权,允许子类通过重写钩子方法来颠覆基本逻辑的执行,这有时候是非常有用的。
模板方法模式结构图

模板方法模式代码结构
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51
| AbstractClass——抽象模板 包含了一个模板方法,(一般为一个具体方法) 给出了一个顶级逻辑的骨架,而逻辑的组成步骤是各个推迟到子类实现的抽象方法。 顶级逻辑也可以调用一些具体方法。
class AbstractClass { public abstract void PrimitiveOperation1( ); public abstract void PrimitiveOperation2( ); public void TemplateMethod( ) { PrimitiveOperation1( ); PrimitiveOperation2( ); } }
ConcreteClass,具体逻辑实现类,实现父类所定义的一个或多个抽象方法。每个AbstractClass都可以由任意多个ConcreteClass与之对应,而每一个ConcreteClass都可以给出这些抽象方法(也就是这些顶级逻辑的任意组成步骤的不同实现),从而使得顶级逻辑的实现各不相同。
ConcreteClassA : AbstractClass { public override void PrimitiveOperation1( ) { } public override void PrimitiveOperation2( ) { } }
ConcreteClassB : AbstractClass { public override void PrimitiveOperation1( ) { } public override void PrimitiveOperation2( ) { } }
客户端调用 AbstractClass c;
c = new AbstractClassA( ); c.TemplateMethod( );
c = new AbstractClassB( ); c.TemplateMethod( );
|
模板方法模式例子——建房子
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108
| public abstract class HouseTemplate { protected HouseTemplate(String name){ this.name = name; } protected String name; protected abstract void buildDoor(); protected abstract void buildWindow(); protected abstract void buildWall(); protected abstract void buildBase(); protected abstract void buildToilet(); protected boolean isBuildToilet(){ return true; } public final void buildHouse(){ buildBase(); buildWall(); buildDoor(); buildWindow(); if(isBuildToilet()){ buildToilet(); } } }
public class HouseOne extends HouseTemplate { HouseOne(String name){ super(name); } HouseOne(String name, boolean isBuildToilet){ this(name); this.isBuildToilet = isBuildToilet; } public boolean isBuildToilet; @Override protected void buildDoor() { System.out.println(name +"的门要采用防盗门"); } @Override protected void buildWindow() { System.out.println(name + "的窗户要面向北方"); } @Override protected void buildWall() { System.out.println(name + "的墙使用大理石建造"); } @Override protected void buildBase() { System.out.println(name + "的地基使用钢铁地基"); } @Override protected void buildToilet() { System.out.println(name + "的厕所建在东南角"); } @Override protected boolean isBuildToilet(){ return isBuildToilet; } }
public class HouseTwo extends HouseTemplate { HouseTwo(String name){ super(name); } @Override protected void buildDoor() { System.out.println(name + "的门采用木门"); } @Override protected void buildWindow() { System.out.println(name + "的窗户要向南"); } @Override protected void buildWall() { System.out.println(name + "的墙使用玻璃制造"); } @Override protected void buildBase() { System.out.println(name + "的地基使用花岗岩"); } @Override protected void buildToilet() { System.out.println(name + "的厕所建在西北角"); } }
public class Clienter { public static void main(String[] args){ HouseTemplate houseOne = new HouseOne("房子1", false); HouseTemplate houseTwo = new HouseTwo("房子2"); houseOne.buildHouse(); houseTwo.buildHouse(); } }
测试结果: 房子1的地基使用钢铁地基 房子1的墙使用大理石建造 房子1的门要采用防盗门 房子1的窗户要面向北方 房子2的地基使用花岗岩 房子2的墙使用玻璃制造 房子2的门采用木门 房子2的窗户要向南 房子2的厕所建在西北角
|
模板方法总结
使用抽象类定义模板类,并在其中定义所有的基本方法、模板方法,钩子方法,不限数量,以实现功能逻辑为主。其中基本方法使用final修饰,其中要调用基本方法和钩子方法,基本方法和钩子方法可以使用protected修饰,表明可被子类修改。
定义实现抽象类的子类,重写其中的模板方法,甚至钩子方法,完善具体的逻辑。
模板方法使用场景
在多个子类中拥有相同的方法,而且逻辑相同时,可以将这些方法抽出来放到一个模板抽象类中。
程序主框架相同,细节不同的情况下,也可以使用模板方法。
模板方法模式的优势