0.参考资料



1.概述

  • 定义一个操作中的算法的骨架 (稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(即复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤。——《设计模式》GoF
  • 模板方法模式(Template Method Pattern),又叫模板模式(Template Pattern),z在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行

1.1动机

  1. - 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
  2. - 在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求.

1.2结构

  1. - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12524106/1629202068871-4bed0b6c-5be3-4fd0-b1c1-b8487144798e.png#clientId=u9a695ff8-36c5-4&from=paste&height=194&id=u2d9de518&margin=%5Bobject%20Object%5D&name=image.png&originHeight=388&originWidth=581&originalType=binary&ratio=1&size=27651&status=done&style=none&taskId=u2868059f-2135-40b0-9d8b-72b97eadc5f&width=290.5)
  2. - 说明:
  3. - AbstractClass 抽象类, 类中实现了模板方法(template),定义了算法的骨架,具体子类需要去实现 其它的抽象方法operationr2,3,4
  4. - ConcreteClass 实现抽象方法operationr2,3,4, 以完成算法中特点子类的步

  1. - 结构化和面对对象设计区别:
  2. - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12524106/1629189221040-2b23ae7f-7214-46a1-af7a-4e8e5b80184c.png#clientId=u2ff7bb69-957a-4&from=paste&height=173&id=u81210cd2&margin=%5Bobject%20Object%5D&name=image.png&originHeight=345&originWidth=645&originalType=binary&ratio=1&size=43086&status=done&style=none&taskId=u2547e74a-d508-41c8-89ca-bb42b774953&width=322.5)
  3. - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12524106/1629189246479-f441654a-6994-429e-819d-764cb2c6d869.png#clientId=u2ff7bb69-957a-4&from=paste&height=167&id=u1e1ddad8&margin=%5Bobject%20Object%5D&name=image.png&originHeight=333&originWidth=647&originalType=binary&ratio=1&size=42640&status=done&style=none&taskId=u84e3ffd4-bce5-4e3b-8f6d-d2d6d1db02d&width=323.5)
  4. - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12524106/1629189270572-c5e66f2f-34a2-4224-83df-18b652b44ee5.png#clientId=u2ff7bb69-957a-4&from=paste&height=168&id=u68dde0e1&margin=%5Bobject%20Object%5D&name=image.png&originHeight=335&originWidth=633&originalType=binary&ratio=1&size=32490&status=done&style=none&taskId=u11068217-63fa-4acc-8531-23307d41d92&width=316.5)

2.要点总结

宏观架构

  1. 1. Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
  2. 1. 除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用。(即 "依赖倒置原则": 实现细节依赖于稳定的抽象)
  3. 1. 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法。

微观代码

  1. 1. 基本思想是:算法只存在于一个地方,也就是在父类中,容易修改。需要修改算法时,只要修改父类的模板方法或者已经实现的某些步骤,子类就会继承这些修改
  2. 1. 实现了最大化代码复用。父类的模板方法和已实现的某些步骤会被子类继承而直接使用。
  3. 1. 既统一了算法,也提供了很大的灵活性。父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。
  4. 1. 该模式的不足之处:每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大
  5. 1. 一般模板方法都加上final关键字, 防止子类重写模板方法.
  6. 1. 模板方法模式使用场景:当要完成在某个过程,该过程要执行一系列步骤 ,这一系列的步骤基本相同,但其个别步骤在实现时 可能不同,通常考虑用模板方法模式来处理

3.案例

略…

4.使用模式

方案

  1. - 一个简单的模板方法模式

钩子方法

  1. - 模板方法模式的父类中,可以定义一个方法,它默认不做任何事,子类可以视情况要不要覆盖它,该方法称为“钩子”。

类图

  1. - ![(TL7HHN91M~3E9198F1{IIU.png](https://cdn.nlark.com/yuque/0/2021/png/12524106/1629202386464-b9b7d704-f4cf-4850-b894-f508afbf3fe7.png#clientId=u9a695ff8-36c5-4&from=paste&height=347&id=ucab89375&margin=%5Bobject%20Object%5D&name=%28TL7HHN91M~3E9198F1%7BIIU.png&originHeight=694&originWidth=673&originalType=binary&ratio=1&size=45379&status=done&style=none&taskId=ua6643412-a39c-4a71-884f-394ade42038&width=336.5)

代码

  1. - AbstractClass
  1. public abstract class AbstractClass {
  2. // 模板方法, final修饰, 防止被重写
  3. public final void templateMethod(){
  4. System.out.println("第1步-----------------");
  5. concreteStep1();
  6. System.out.println("第2步-----------------");
  7. concreteStep3();
  8. System.out.println("第3步-----------------");
  9. // 使用(抽象)钩子方法判断是否进行 step5
  10. if (step2()){
  11. System.out.println("第4步-----------------准备循环");
  12. // 调用抽象方法step4, 判断实际的step5进行次数
  13. for (int i = step4(), count = 0; i > 0; i--){
  14. System.out.println("第4步-----------------" + ++count);
  15. concreteStep5();
  16. }
  17. }
  18. }
  19. public void concreteStep1(){
  20. System.out.println("step1:启动");
  21. }
  22. public void concreteStep3(){
  23. System.out.println("step3: 启动成功");
  24. }
  25. public void concreteStep5(){
  26. System.out.println("step5: 扩展");
  27. }
  28. /**
  29. * @description: 钩子方法, 默认不做任何事
  30. */
  31. protected boolean step2(){
  32. return false;
  33. };
  34. protected abstract int step4();
  35. }
  1. - ConcreteClass
  1. public class ConcreteClass extends AbstractClass{
  2. @Override
  3. protected boolean step2() {
  4. boolean flag = true;
  5. System.out.println("step2: 判断中--" + flag);
  6. return flag;
  7. }
  8. @Override
  9. protected int step4() {
  10. int count = 3;
  11. System.out.println("step4: 准备循环" + count);
  12. return count;
  13. }
  14. }
  1. - 测试客户端及结果
  1. public class Client {
  2. public static void main(String[] args) {
  3. AbstractClass concreteClass = new ConcreteClass();
  4. concreteClass.templateMethod();
  5. }
  6. }
  1. 1步-----------------
  2. step1:启动
  3. 2步-----------------
  4. step3: 启动成功
  5. 3步-----------------
  6. step2: 判断中--true
  7. 4步-----------------准备循环
  8. step4: 准备循环3
  9. 4步-----------------1
  10. step5: 扩展
  11. 4步-----------------2
  12. step5: 扩展
  13. 4步-----------------3
  14. step5: 扩展

5.经典使用


5.1Spring中IOC容器的初始化

5.1源码分析

  1. - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12524106/1629203260711-cb4dd773-f667-4e96-ae5f-f406f102b555.png#clientId=u9a695ff8-36c5-4&from=paste&height=292&id=ufa868354&margin=%5Bobject%20Object%5D&name=image.png&originHeight=584&originWidth=1032&originalType=binary&ratio=1&size=1010647&status=done&style=none&taskId=u1c5d56f8-f909-4131-bdfe-cde72b0e1a0&width=516)

5.2类图

  1. - ![image.png](https://cdn.nlark.com/yuque/0/2021/png/12524106/1629203303733-ba5e4322-7ea8-4c35-b683-b26e43178c0b.png#clientId=u9a695ff8-36c5-4&from=paste&height=292&id=u8bf94a0c&margin=%5Bobject%20Object%5D&name=image.png&originHeight=584&originWidth=1110&originalType=binary&ratio=1&size=376669&status=done&style=none&taskId=u5ae6a4b4-2cfc-4c08-a542-668bbb99bb0&width=555)

5.2JavaWeb中HttpServlet抽象类的service(…)

说明:

  1. - 方法功能: 把处理具体HTTP请求的流程构建好, 但是具体业务的具体请求是不确定的(即doGet/doPost等), 所以封装成service(...), 再获取请求头信息确定具体执行的HTTP请求类型. 最后该请求类型的具体实现则由其具体子类实现. HttpServlet中的各种doXxx(...)均是异常方法, 根据具体业务具体实现
  2. - HttpServlet中, service(...) 即是模板方法. 其中的各种将抛出异常的 doXxx(...)均是钩子方法
  1. protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  2. String method = req.getMethod();
  3. long lastModified;
  4. if (method.equals("GET")) {
  5. lastModified = this.getLastModified(req);
  6. if (lastModified == -1L) {
  7. this.doGet(req, resp);
  8. } else {
  9. long ifModifiedSince;
  10. try {
  11. ifModifiedSince = req.getDateHeader("If-Modified-Since");
  12. } catch (IllegalArgumentException var9) {
  13. ifModifiedSince = -1L;
  14. }
  15. if (ifModifiedSince < lastModified / 1000L * 1000L) {
  16. this.maybeSetLastModified(resp, lastModified);
  17. this.doGet(req, resp);
  18. } else {
  19. resp.setStatus(304);
  20. }
  21. }
  22. } else if (method.equals("HEAD")) {
  23. lastModified = this.getLastModified(req);
  24. this.maybeSetLastModified(resp, lastModified);
  25. this.doHead(req, resp);
  26. } else if (method.equals("POST")) {
  27. this.doPost(req, resp);
  28. } else if (method.equals("PUT")) {
  29. this.doPut(req, resp);
  30. } else if (method.equals("DELETE")) {
  31. this.doDelete(req, resp);
  32. } else if (method.equals("OPTIONS")) {
  33. this.doOptions(req, resp);
  34. } else if (method.equals("TRACE")) {
  35. this.doTrace(req, resp);
  36. } else {
  37. String errMsg = lStrings.getString("http.method_not_implemented");
  38. Object[] errArgs = new Object[]{method};
  39. errMsg = MessageFormat.format(errMsg, errArgs);
  40. resp.sendError(501, errMsg);
  41. }
  42. }
  43. protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
  44. String protocol = req.getProtocol();
  45. String msg = lStrings.getString("http.method_get_not_supported");
  46. if (protocol.endsWith("1.1")) {
  47. resp.sendError(405, msg);
  48. } else {
  49. resp.sendError(400, msg);
  50. }
  51. }