模式说明

有这样一些对象,他们都要执行若干动作,这些动作中多数类似或完全相同,例如在不同客户在到银行处理业务,都需要取号,排队,与柜员交流,处理后对服务评分等。在这里取号,排队,评分动作是完全相同的,与柜员交流的细节可能不同,可能是办理存款业务,也可能是取款,购买基金等。针对此类场景,可以将设置一个抽象模板类,类内声明相关方法,再定义一个驱动方法来调用这些相关方法。这样子类继承抽象模板类后自动复用了大部分的代码,对于具体实现中有区别的细节,在子类中重写即可。

本示例以大学生和小学生入学活动为例,将入学活动中相同的部分放在抽象模板类中,子类继承时自动获得,而子类中不同部分在抽象类中定义为抽象方法或钩子方法,具体实现延迟到子类中。

结构

抽象模板类
定义方法骨架,并确定一个procedure方法,将需要执行的方法集中放置其中,客户端调用该procedure即可统一执行多个既定的方法。该类内方法分为普通方法,抽象方法和钩子方法。
具体实现类
继承抽象模板类,按自身情况实现其中的各种方法。

代码演示

  1. package com.yukiyama.pattern.behavior;
  2. /**
  3. * 模板方法模式
  4. */
  5. public class TemplateMethodDemo {
  6. public static void main(String[] args) {
  7. Admission ad1 = new CollegeAdmission();
  8. System.out.println("====大学生的入学活动====");
  9. ad1.templateProcedure();
  10. System.out.println("====小学生的入学活动====");
  11. Admission ad2 = new PrimarySchoolAdmission();
  12. ad2.templateProcedure();
  13. }
  14. }
  15. /**
  16. * 抽象模板类
  17. * 定义方法骨架,并确定一个procedure方法,将需要执行的方法集中放置,客户端
  18. * 调用该procedure即可统一执行多个既定的方法。该类内方法分为普通方法,抽象
  19. * 方法和钩子方法。普通方法是所有子类均的共同步骤,且细节一致。抽象方法也是
  20. * 共同步骤,但细节不同,延迟到子类中实现。钩子方法分为简单钩子和挂载钩子方法。
  21. * 对于简单钩子方法,抽象类中将其声明为空方法体的普通方法,子类可以选择重写
  22. * 扩展,若不重写则执行空方法体(相当于不执行)。对于挂载钩子方法,抽象类中先
  23. * 定义一个用于判断是否执行挂载钩子方法的返回boolean类型的抽象方法。再在挂载
  24. * 钩子方法中通过一个if-else判断上述boolean类型方法的返回值,true则执行,
  25. * false则进入空分支(相当于不执行)。boolean类型抽象方法延迟到子类实现,由
  26. * 子类决定是否进入执行挂载钩子方法的执行分支。挂载钩子方法本身在抽象类中可以
  27. * 作为普通方法,这样子类中就不必重写了。
  28. */
  29. abstract class Admission{
  30. public void templateProcedure() {
  31. healthCheck();
  32. payTuition();
  33. militaryTraining();
  34. morningExercise();
  35. registerClasses();
  36. }
  37. public void healthCheck() {
  38. System.out.println("到教育部指定体检机构体检。");
  39. }
  40. public void payTuition() {
  41. System.out.println("通过教育部统一学费缴纳平台缴费。");
  42. }
  43. // 将军训设置为一个简单钩子方法,具体实现类可选择实现
  44. public void militaryTraining() {};
  45. // 将早操设置为一个挂载钩子方法,具体实现类中先实现hasMorningExcercise,
  46. // true则执行(要做早操),false不执行(进入空分支,相当于不执行)
  47. public abstract boolean hasMorningExcercise();
  48. public void morningExercise() {
  49. if(hasMorningExcercise()) {
  50. System.out.println("要做早操。");
  51. } else {}
  52. }
  53. public abstract void registerClasses();
  54. public abstract void choseDormitory();
  55. }
  56. /**
  57. * 具体实现类
  58. * 继承抽象模板类,按自身情况实现其中的各种方法。
  59. * 下例是大学生入学活动类。
  60. */
  61. class CollegeAdmission extends Admission {
  62. // 具体实现类中扩展钩子方法
  63. @Override
  64. public void militaryTraining() {
  65. System.out.println("高校新生入学后要参加军训。");
  66. }
  67. // 重写抽象类中的挂载钩子方法的触发方法
  68. @Override
  69. public boolean hasMorningExcercise() {
  70. return false;
  71. }
  72. @Override
  73. public void registerClasses() {
  74. System.out.println("高校新生课程注册由新生自行完成。");
  75. }
  76. @Override
  77. public void choseDormitory() {
  78. System.out.println("高校新生入学后请在校内宿舍系统内选择宿舍。");
  79. }
  80. }
  81. /**
  82. * 具体实现类
  83. * 下例是小学生入学活动类。
  84. */
  85. class PrimarySchoolAdmission extends Admission{
  86. // 没有实现抽象类中的简单钩子方法militaryTraining
  87. // 重写抽象类中的挂载钩子方法的触发方法
  88. @Override
  89. public boolean hasMorningExcercise() {
  90. return true;
  91. }
  92. @Override
  93. public void registerClasses() {
  94. System.out.println("小学新生课程注册由班主任完成。");
  95. }
  96. @Override
  97. public void choseDormitory() {
  98. System.out.println("小学新生原则上不提供校内住宿,特殊情况请单独申请。");
  99. }
  100. }