概述
????文章示例代码????
附链
你也可以在这些平台阅读本文:
- 语雀
- 个人博客
定义
定义一个算法的步骤,并允许子类为一个或者多个步骤提供实现。
模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤。
场景示例
笔者这里以做番茄炒蛋为例。笔者将做番茄炒蛋的步骤分为以下几步:倒油、放鸡蛋、放番茄、倒调料、翻炒。不考虑多余的细节问题,不同的人做番茄炒蛋的步骤应该是类似的。
创建抽象模板
这里主要定义炒菜的步骤。
/**
* @author zhh
* @description 抽象模板类
* @date 2020-02-27 15:47
*/
public abstract class AbstractCook {
/**
* 做饭的整体步骤
*/
protected final void cook() {
this.pourOil();
this.addEgg();
this.addTomato();
this.pourSeasoning();
this.stirFry();
if (needChoppedGreenOnion()) {
this.addChoppedGreenOnion();
}
}
/**
* 倒油
*/
final void pourOil() {
System.out.println("倒入食用油");
}
/**
* 放鸡蛋
*/
final void addEgg() {
System.out.println("放入鸡蛋");
}
/**
* 放番茄
*/
final void addTomato() {
System.out.println("放入番茄");
}
/**
* 翻炒
*/
final void stirFry() {
System.out.println("快速翻炒");
}
/**
* 放葱花
*/
final void addChoppedGreenOnion() {
System.out.println("放点葱花");
}
/**
* 是否需要葱花 (钩子方法)
*/
protected boolean needChoppedGreenOnion() {
return false;
}
/**
* 倒调味品
*/
abstract void pourSeasoning();
}
这里的 needChoppedGreenOnion()
是一个钩子方法,让具体的子类来决定是否添加葱花,默认不添加。
以上的部分方法用 final
修饰,是为了防止子类对其进行重写。
创建具体子类
这里以笔者做饭和女朋友做饭为例。由于两人的口味不同,倒入的调味品会存在些许差异。而且笔者喜欢在番茄炒蛋中加入葱花。
/**
* @author zhh
* @description 具体子类
* @date 2020-02-27 16:04
*/
public class MeCook extends AbstractCook {
@Override
void pourSeasoning() {
System.out.println("放点盐");
System.out.println("放点酱油");
}
/**
* 此处覆盖了父类钩子方法的默认实现
*/
@Override
protected boolean needChoppedGreenOnion() {
return true;
}
}
/**
* @author zhh
* @description 具体子类
* @date 2020-02-27 16:07
*/
public class GirlFriendCook extends AbstractCook {
@Override
void pourSeasoning() {
System.out.println("放点盐");
}
}
我们可以看到在 MeCook
类中重写了父类的 needChoppedGreenOnion()
方法,那么对于父类中模板方法执行 needChoppedGreenOnion()
方法时,拿到的其实是子类方法的返回值。
测试类及输出
/**
* @author zhh
* @description 测试类
* @date 2020-02-27 16:13
*/
public class Test {
public static void main(String[] args) {
// 我做番茄炒蛋
System.out.println("---我做番茄炒蛋 开始---");
AbstractCook meCook = new MeCook();
meCook.cook();
System.out.println("---我做番茄炒蛋 结束---");
// 女朋友做番茄炒蛋
System.out.println("---女朋友做番茄炒蛋 开始---");
AbstractCook girlFriendCook = new GirlFriendCook();
girlFriendCook.cook();
System.out.println("---女朋友做番茄炒蛋 结束---");
}
}
测试类输出的结果如下:
—我做番茄炒蛋 开始—
倒入食用油
放入鸡蛋
放入番茄
放点盐
放点酱油
快速翻炒
放点葱花
—我做番茄炒蛋 结束—
—女朋友做番茄炒蛋 开始—
倒入食用油
放入鸡蛋
放入番茄
放点盐
快速翻炒
—女朋友做番茄炒蛋 结束—
类结构图
以上示例类的结构图如下所示
总结
适用场景
- 算法的整体步骤固定,但其中的个别部分易变。
- 多个子类存在公共的行为,可以将其提取出来并且集中到一个公共父类当中,避免代码重复。
优点
- 父类提供公共部分代码,提高复用性。
- 将不变部分的算法封装到父类中实现,把可变部分的算法由子类继承去实现,提高了扩展性。
缺点
- 对于每个不同的实现都需要一个子类来实现,导致类数目的增加,增加系统实现的复杂度。
- 父类中的抽象方法由自子类实现,如果父类添加新的抽象方法,所有的子类都需要修改。
扩展
钩子方法:提供缺省行为,子类可以在必要时进行扩展。
参考
- 《Head First 设计模式》
- 《大话设计模式》
- 维基百科-模板方法
- 菜鸟教程-模板模式
最后
以上就是激动眼睛为你收集整理的Java设计模式之行为型-模板方法模式 (Template Method)附链定义场景示例总结参考的全部内容,希望文章能够帮你解决Java设计模式之行为型-模板方法模式 (Template Method)附链定义场景示例总结参考所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复