前言
在上一篇文章责任链模式
中提到了模板方法模式,因此这里简单介绍一下.
模板方法模式比较简单,或者说比较常用.在开发过程中,许多人在不知不觉的情况下就会使用,只要他具有良好的面对对象思维.
比如当你写了Dog
和Cat
两个类,发现很多相同的代码,你自然就会将相同模块提取抽象成父类,然后将一些公共的方法放到父类中,这样子就基本实现了模板方式模式.
介绍(摘自《Head FIrst 设计模式》)
在一个方法中定义一个算法的骨架,而将一些详细的步骤延迟到子类中.
模板方法使得子类可以在不改变算法结果的基础上,重新定义算法中的某些步骤.
类图
角色
抽象模板: 抽象模板一般有一个具体实现的方法,用来定义算法的基础骨架.还有一些抽象方法留给子类去具体实现.此外还有一些有默认实现的钩子方法.子类可选实现.
具体模板: 继承父类的具体方法,实现他们的抽象方法,对于钩子方法,可以根据自身情况决定是都重写.
举个栗子
书上的例子好多了,网络上也有很多,我自己临时瞎想一个吧,不保证一定合适.
假如我们现在要实现两个类,Dog
和Cat
,并且实现他们的进攻方法.
我们大致实现以下,如下.
Cat:
1 | package design_patterns.template_pattern; |
Dog:
1 | package design_patterns.template_pattern; |
仔细查看代码,发现其实他们的攻击过程很相似.
狗:准备,跑过去,发出声音,咬住
猫:准备,跳过去,咬住
但是这样子编码的话,我们将相同的prepared
和bite
分别写了两次,这是不科学的.
很明显我们可以实现一个父类,将prepared
和bite
在父类里实现他们分别继承就好了.
那么对于shout
和jump/run
方法呢?就分别实现了嘛?
不是的,jump
和run
都是移动,只是实现方法不同,也是可以抽象到父类的,那么shout
呢?这就是钩子的作用了,可以动态控制当前动物是否会发出声音之后再进行攻击
.
改进后的代码如下:
首先是动物模板类:
1 | package design_patterns.template_pattern; |
注意,代码中的setShout
是钩子方法,这里简单的用一个变量来当做钩子,此外,prepared
和bite
是具体方法,而move
和shout
为抽象方法.
下面是狗的具体实现:
1 | package design_patterns.template_pattern; |
猫的具体实现:
1 | package design_patterns.template_pattern; |
测试类:
1 | package design_patterns.template_pattern; |
输出结果:
1 | 准备 |
对比上下的代码可以发现,在第二个版本中,没有一些重复的代码,且子类的逻辑更加清晰,仅仅实现了自己与其他类不相同的部分,或者自己想要实现的部分钩子方法.
而且当动物越来越多,代码的总量会越来越少且容易维护,新添加一个动物,只需要继承动物模板,然后实现move
和shout
即可.
总结
首先注意一下:在模板方法的attack
上,添加了final
关键字,可以防止该方法被重写,可以保证attack
这一方法,在定义及流程上的正确性及安全性,而具体的实现可以交给子类.
模板方法的优点:
1、封装不变部分,扩展可变部分。
2、提取公共代码,便于维护。
3、行为由父类控制,子类实现。
缺点:
类的个数较多.
完。
ChangeLog
2019-03-20 完成以上皆为个人所思所得,如有错误欢迎评论区指正。
欢迎转载,烦请署名并保留原文链接。
更多学习笔记见个人博客——>呼延十