0.参考资料
1.概述
- 定义一个操作中的算法的骨架 (稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(即复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤。——《设计模式》GoF
- 模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),z在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
1.1动机
- 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。- 在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求.
1.2结构
- - 说明:- AbstractClass 抽象类, 类中实现了模板方法(template),定义了算法的骨架,具体子类需要去实现 其它的抽象方法operationr2,3,4- ConcreteClass 实现抽象方法operationr2,3,4, 以完成算法中特点子类的步
骤
- 结构化和面对对象设计区别:- - - 
2.要点总结
宏观架构
1. Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。1. 除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用。(即 "依赖倒置原则": 实现细节依赖于稳定的抽象)1. 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法。
微观代码
1. 基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改1. 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。1. 既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。1. 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大1. 一般模板方法都加上final关键字, 防止子类重写模板方法.1. 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时 可能不同,通常考虑用模板方法模式来处理
3.案例
略…
4.使用模式
方案
- 一个简单的模板方法模式
钩子方法
- 模板方法模式的父类中,可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。
类图
- 
代码
- AbstractClass
public abstract class AbstractClass {// 模板方法, final修饰, 防止被重写public final void templateMethod(){System.out.println("第1步-----------------");concreteStep1();System.out.println("第2步-----------------");concreteStep3();System.out.println("第3步-----------------");// 使用(抽象)钩子方法判断是否进行 step5if (step2()){System.out.println("第4步-----------------准备循环");// 调用抽象方法step4, 判断实际的step5进行次数for (int i = step4(), count = 0; i > 0; i--){System.out.println("第4步-----------------" + ++count);concreteStep5();}}}public void concreteStep1(){System.out.println("step1:启动");}public void concreteStep3(){System.out.println("step3: 启动成功");}public void concreteStep5(){System.out.println("step5: 扩展");}/*** @description: 钩子方法, 默认不做任何事*/protected boolean step2(){return false;};protected abstract int step4();}
- ConcreteClass
public class ConcreteClass extends AbstractClass{@Overrideprotected boolean step2() {boolean flag = true;System.out.println("step2: 判断中--" + flag);return flag;}@Overrideprotected int step4() {int count = 3;System.out.println("step4: 准备循环" + count);return count;}}
- 测试客户端及结果
public class Client {public static void main(String[] args) {AbstractClass concreteClass = new ConcreteClass();concreteClass.templateMethod();}}
第1步-----------------step1:启动第2步-----------------step3: 启动成功第3步-----------------step2: 判断中--true第4步-----------------准备循环step4: 准备循环3第4步-----------------1step5: 扩展第4步-----------------2step5: 扩展第4步-----------------3step5: 扩展
5.经典使用
5.1Spring中IOC容器的初始化
5.1源码分析
- 
5.2类图
- 
5.2JavaWeb中HttpServlet抽象类的service(…)
说明:
- 方法功能: 把处理具体HTTP请求的流程构建好, 但是具体业务的具体请求是不确定的(即doGet/doPost等), 所以封装成service(...), 再获取请求头信息确定具体执行的HTTP请求类型. 最后该请求类型的具体实现则由其具体子类实现. HttpServlet中的各种doXxx(...)均是异常方法, 根据具体业务具体实现- HttpServlet中, service(...) 即是模板方法. 其中的各种将抛出异常的 doXxx(...)均是钩子方法
protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String method = req.getMethod();long lastModified;if (method.equals("GET")) {lastModified = this.getLastModified(req);if (lastModified == -1L) {this.doGet(req, resp);} else {long ifModifiedSince;try {ifModifiedSince = req.getDateHeader("If-Modified-Since");} catch (IllegalArgumentException var9) {ifModifiedSince = -1L;}if (ifModifiedSince < lastModified / 1000L * 1000L) {this.maybeSetLastModified(resp, lastModified);this.doGet(req, resp);} else {resp.setStatus(304);}}} else if (method.equals("HEAD")) {lastModified = this.getLastModified(req);this.maybeSetLastModified(resp, lastModified);this.doHead(req, resp);} else if (method.equals("POST")) {this.doPost(req, resp);} else if (method.equals("PUT")) {this.doPut(req, resp);} else if (method.equals("DELETE")) {this.doDelete(req, resp);} else if (method.equals("OPTIONS")) {this.doOptions(req, resp);} else if (method.equals("TRACE")) {this.doTrace(req, resp);} else {String errMsg = lStrings.getString("http.method_not_implemented");Object[] errArgs = new Object[]{method};errMsg = MessageFormat.format(errMsg, errArgs);resp.sendError(501, errMsg);}}protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {String protocol = req.getProtocol();String msg = lStrings.getString("http.method_get_not_supported");if (protocol.endsWith("1.1")) {resp.sendError(405, msg);} else {resp.sendError(400, msg);}}
