相信自己,请一定要相信自己
上一章简单介绍了代理模式(十五), 如果没有看过, 请观看上一章
一. 模板模式
引用 菜鸟教程里面的 模板模式介绍: https://www.runoob.com/design-pattern/template-pattern.html
在模板模式(Template Pattern)中,一个抽象类公开定义了执行它的方法的方式/模板。
它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。这种类型的设计模式属于行为型模式。
一.一 介绍
意图: 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤。
主要解决 一些方法通用,却在每一个子类都重新写了这一方法。
何时使用: 有一些通用的方法。
如何解决: 将这些通用算法抽象出来。
关键代码: 在抽象类实现,其他步骤在子类实现。
应用实例: 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。 3、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
优点: 1、封装不变部分,扩展可变部分。 2、提取公共代码,便于维护。 3、行为由父类控制,子类实现。
缺点 每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
使用场景: 1、有多个子类共有的方法,且逻辑相同。 2、重要的、复杂的方法,可以考虑作为模板方法。
注意事项: 为防止恶意操作,一般模板方法都加上 final 关键词。
二. 模板模式应用
定义一个操作中算法的骨架,而将一些步骤延迟到子类中, 模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。
通俗点讲: 完成一件事情,有固定的数个步骤, 但是每个步骤根据对象的不同,而实现细节不同,
就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤云调用其每个步骤的实现方法。
每个步骤的具体实现,由子类完成。
二.一. 制作牛奶的例子
二.一.一 定义抽象类
@Slf4j
public abstract class Milk {
public final void make() {
select();
if (customerCondiments()) {
addCondiments();
}
soak();
beat();
}
void select() {
log.info("第一步,选择好的黄豆");
}
// 添加信息,由子类去实现
protected abstract void addCondiments();
void soak() {
log.info("第三步, 浸泡 3个小时");
}
void beat() {
log.info("第四步: 打碎");
}
protected boolean customerCondiments() {
return true;
}
}
二.一.二 不同的实现
无任何添加的
@Slf4j
public class NoMilk extends Milk{
@Override
protected boolean customerCondiments() {
return false;
}
@Override
protected void addCondiments() {
}
}
红豆的:
@Slf4j
public class RedDou extends Milk{
@Override
public void addCondiments() {
log.info("第二步,添加红豆");
}
}
花生的:
@Slf4j
public class HuaShengMilk extends Milk{
@Override
public void addCondiments() {
log.info("第二步,添加花生");
}
}
二.一.三 测试验证
@Test
public void oneTest() {
Milk milk = new HuaShengMilk();
milk.make();
}
@Test
public void twoTest() {
Milk noMilk = new NoMilk();
noMilk.make();
}
二.二 做饭例子
二.二.一 做饭抽象类
public abstract class Food {
public void cookFood() {
preparation();
make();
put();
eat();
}
protected abstract void preparation();
protected abstract void make();
protected abstract void put();
protected abstract void eat();
}
二.二.二 实现子类
做鱼
@Slf4j
public class Fish extends Food{
@Override
protected void preparation() {
log.info(">>> 准备买好的,已经处理过的活,简单再处理");
}
@Override
protected void make() {
log.info("烧水,把鱼放进去");
}
@Override
protected void put() {
log.info("把鱼放盘子里面,端上来");
}
@Override
protected void eat() {
log.info("吃鱼");
}
}
下面条:
@Slf4j
public class Noodles extends Food {
@Override
protected void preparation() {
log.info("准备面条,切葱花,烧开水");
}
@Override
protected void make() {
log.info("把面条放置滚水里面");
}
@Override
protected void put() {
log.info("捞出来,放碗里");
}
@Override
protected void eat() {
log.info("开始吃面条");
}
}
二.二.三 测试方法
@Test
public void foodTest() {
Food food = new Fish();
food.cookFood();
food = new Noodles();
food.cookFood();
}
优点:
- 具体细节步骤实现在子类中,子类定义详细处理算法 是不会改变算法整体结构的。
- 代码复用的基本技术,在数据库设计中特别重要
- 存在一种反向的控制结构, 通过一个低头调用其子类 操作,通过子类对父类进行扩展增加新的行为,
符合开闭原则。
缺点:
每个不同的实现都需要定义一个子类,会导致类的个数增加,系统会变得庞大。
本章节的代码放置在 github 上:
https://github.com/yuejianli/DesignPattern/tree/develop/Template
谢谢您的观看,如果喜欢,请关注我,再次感谢 !!!