设计模式系列----模板方法模式理解
什么是模板方法模式
模板方法模式在一个方法中定义一个算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤.
模板方法的使用场景
当两个类相似度极高,除了一两个方法不相同,其他的所有方法都相同时,可以通过模板方法,将相似的方法抽取出来,在抽象父类实现,不相似的方法使用abstrat修饰,强迫子类自己分别实现不相似的方法。相同的方法在父类实现了。
代码例子:
抽象父类
//豆浆类,抽象类
public abstract class SoyaMilk {
//这是模板方法,用final修饰,不允许子类覆盖。模板方法定义了制作豆浆的程序
final void prepareRecipe(){
selectMaterial();
addCondiments();
soak();
beat();
}
//选材方法,选择黄豆
void selectMaterial(){
System.out.println("第一步、选择好了新鲜黄豆");
}
//可以添加不同的配料,在这里设置为抽象方法,子类必须实现
abstract void addCondiments();
//浸泡
void soak(){
System.out.println("第三步、黄豆和配料开始浸泡,大概需要5个小时");
}
//放到豆浆机打碎
void beat(){
System.out.println("第四步、黄豆的配料放到豆浆机打碎");
}
}
制作红枣豆浆
//红枣豆浆
public class ReddatesSoyaMilk extends SoyaMilk{
//实现父类的添加配料方法
@Override
void addCondiments() {
System.out.println("第二步、添加红枣配料");
}
}
制造核桃豆浆
//核桃豆浆
public class NutSoyaMilk extends SoyaMilk{
//实现父类的添加配料方法
@Override
void addCondiments() {
System.out.println("第二步、添加核桃配料");
}
}
测试制作豆浆
public class SoyaMilkTest {
public static void main(String[] args){
//制作红枣豆浆
System.out.println();
System.out.println("-----制作红枣豆浆步骤-------");
SoyaMilk reddatesSoyaMilk = new ReddatesSoyaMilk();
reddatesSoyaMilk.prepareRecipe();
//制作核桃豆浆
System.out.println();
System.out.println("-----制作核桃豆浆步骤-------");
SoyaMilk nutSoyaMilk = new NutSoyaMilk();
nutSoyaMilk.prepareRecipe();
}
}
如果后续还要制作其他豆浆,只需要定义一个子类继承父类并实现抽象方法即可,符合开闭原则
钩子方法
并且模板方法模式中,还有钩子方法的概念:
钩子方法的作用
1、让子类实现算法中的可选部分。算法中的某些步骤是可选的,子类可以做出决定是否需要这些步骤。
2、如果钩子对于子类的实现不重要时,子类可以对钩子置之不理。
3、钩子可以让子类能够有机会对模板方法中某些即将发生的(或刚刚发生的)步骤作出反应。可以在钩子中实现我们对于某个步骤执行需要作出的动作,模板方法的某个步骤执行时,调用钩子。
我们对方法进行改造
1、创建有钩子方法的父类
//豆浆类,抽象类
public abstract class SoyaMilkWithHook {
//这是模板方法,用final修饰,不允许子类覆盖。模板方法定义了制作豆浆的程序
final void prepareRecipe(){
selectMaterial();
//判断是否添加配料
if(customerWantsCondiments()){
addCondiments();
}
soak();
beat();
}
//选材方法,选择黄豆
void selectMaterial(){
System.out.println("选择好了新鲜黄豆");
}
//可以添加不同的配料,在这里设置为抽象方法,子类必须实现
abstract void addCondiments();
//浸泡
void soak(){
System.out.println("材料开始浸泡,大概需要5个小时");
}
//放到豆浆机打碎
void beat(){
System.out.println("材料放到豆浆机打碎");
}
//钩子方法,是否添加配料
boolean customerWantsCondiments(){
return true;
}
}
2、创建纯豆浆子类
//制作纯豆浆,不添加任何配料
public class PureSoyaMilk extends SoyaMilkWithHook{
@Override
void addCondiments() {
}
//覆盖钩子方法,不添加配料
@Override
boolean customerWantsCondiments(){
return false;
}
}
3、测试制作纯豆浆
public class PureSoyaMilkTest {
public static void main(String[] args){
//制作纯豆浆
System.out.println();
System.out.println("-----制作纯豆浆步骤-------");
SoyaMilkWithHook pureSoyaMilk = new PureSoyaMilk();
pureSoyaMilk.prepareRecipe();
}
}
实现了某些步骤可选
–我是“道祖且长”,一个在互联网"苟且偷生"的Java程序员
“有任何问题,可评论,我看到就会回复”
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)