模板方法模式(Template Method Pattern),定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
**
在面向对象程序设计过程中,程序员常常会遇到这种情况:设计一个系统时知道了算法所需的关键步骤,而且确定了这些步骤的执行顺序,但某些步骤的具体实现还未知,或者说某些步骤的实现与具体的环境相关。

例如,去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、对银行工作人员进行评分等,其中取号、排队和对银行工作人员进行评分的业务对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。这种场景就可以使用模板方法模式思想实现。

模板方法模式组成如下:

  1. Abstract Class(抽象模板)

抽象模板类,负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。这些方法的定义如下:

① 模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法

② 基本方法:是整个算法中的一个步骤,包含以下几种类型:

  • 抽象方法:在抽象类中声明,由具体子类实现
  • 具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它
  • 钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种
  1. Concrete Class(具体实现)

具体实现类,实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的一个组成步骤。

模板方法模式的优点

  1. 它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展
  2. 它在父类中提取了公共的部分代码,便于代码复用
  3. 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则

模板方法模式的缺点

  1. 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度
  2. 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度
  3. 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍

模板方法模式使用场景

  1. 算法的整体步骤很固定,但其中个别部分易变时,这时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现
  2. 当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。首先,要识别现有代码中的不同之处,并且将不同之处分离为新的操作。最后,用一个调用这些新的操作的模板方法来替换这些不同的代码
  3. 当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展

模板方法模式使用示例

通过不同的方式追求心爱的姑娘。

  1. public class TemplatePattern {
  2. static abstract class Seek {
  3. protected void seekGirl() {
  4. // 公共步骤,第一步
  5. System.out.println("首先,寻找自己喜欢的姑娘");
  6. if (seekSuccess()) {
  7. afterSeek();
  8. }
  9. }
  10. /**
  11. * 钩子方法,是否又进行下一步的必要
  12. *
  13. * @return
  14. */
  15. protected abstract boolean seekSuccess();
  16. private void afterSeek() {
  17. System.out.println("追求成功,准备迈向幸福的大门...");
  18. }
  19. }
  20. /**
  21. * 送礼物
  22. */
  23. static class GiftSeek extends Seek {
  24. @Override
  25. protected boolean seekSuccess() {
  26. System.out.println("送她喜欢的小动物——捷豹,宝马等...");
  27. return true;
  28. }
  29. }
  30. /**
  31. * 文采出众,吸引她
  32. */
  33. static class ArtisticSeek extends Seek {
  34. @Override
  35. protected boolean seekSuccess() {
  36. System.out.println("为她写诗,感动她...");
  37. return false;
  38. }
  39. }
  40. public static void main(String[] args) {
  41. GiftSeek giftSeek = new GiftSeek();
  42. giftSeek.seekGirl();
  43. ArtisticSeek artisticSeek = new ArtisticSeek();
  44. artisticSeek.seekGirl();
  45. }
  46. }

程序运行结果如下:

:::success 首先,寻找自己喜欢的姑娘
送她喜欢的小动物——捷豹,宝马等…
追求成功,准备迈向幸福的大门…

首先,寻找自己喜欢的姑娘
为她写诗,感动她… :::