? 作者主页:欢迎来到我的技术博客😎
? 个人介绍:大家好,本人热衷于Java后端开发,欢迎来交流学习哦!( ̄▽ ̄)~*
🍊 如果文章对您有帮助,记得关注、点赞、收藏、评论??????
📣 您的支持将是我创作的动力,让我们一起加油进步吧!!!🎉🎉
在软件开发中,某个方法的实现需要多个步骤,其中有些步骤是固定的,而有些步骤并不固定,存在可变性。为了提高代码的复用性和系统的灵活性,可以使用 模板方法模式 的设计模式对这类情况进行设计。
在模板方法模式中将实现功能的每一步骤所对应的方法称为 基本方法,而将调用这些基本方法同时定义基本方法的执行次序的方法称为 模板方法。
定义: 定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
模板方法模式将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称为模板方法的方法的定义这些基本方法的执行次序,并且可以通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。
模板方法模式包含以下重要角色:
抽象类 : 负责给出一个算法的轮廓和骨架。它由一个模板方法和若干个基本方法构成。
模板方法 : 定义了算法的骨架,按某种顺序调用其包含的基本方法。
基本方法 : 是实现算法中各个步骤的方法,是模板方法的组成部分。基本方法又可以分为三种:
isXxx
,返回值类型为 boolean
类型。具体子类 : 实现抽象类中所定义的抽象方法和钩子方法,它们是一个顶级逻辑的组成步骤。
需求案例:去银行办理业务一般要经过以下4个流程:取号、排队、办理具体业务、离开银行等操作。
我们可以发现,在这个流程中取号、排队和对离开银行的操作对每个客户是一样的,可以在父类中实现,但是办理具体业务却因人而异,它可能是存款、取款或者转账等,可以延迟到子类中实现。
现在使用模板方法模式来实现上述案例,类图如下:
?
具体的类设计如下:
抽象类:
public abstract class AbstractClass {
//模板方法(定义基本方法的执行顺序)
public final void service() {
getNum();
doWait();
doService();
doExit();
}
//下面的方法都称为基本方法
//第一步:取号(一样的,所以直接实现)
public void getNum() {
System.out.println("取号");
}
//第二部:排队(一样的,所以直接实现)
public void doWait() {
System.out.println("排队");
}
//第三步:办理具体业务(不一样,由子类实现)
public abstract void doService();
//第四步:离开银行(一样的,所以直接实现)
public void doExit() {
System.out.println("离开银行");
}
}
存款业务类:
public class SaveMoney extends AbstractClass {
public void doService() {
System.out.println("办理存款业务");
}
}
取款业务类:
public class TakeMoney extends AbstractClass {
public void doService() {
System.out.println("办理取款业务");
}
}
客户端类:
public class client {
public static void main(String[] args) {
//办理存款业务
SaveMoney saveMoney = new SaveMoney();
saveMoney.service();
System.out.println("---------------");
//办理取款业务
TakeMoney takeMoney = new TakeMoney();
takeMoney.service();
}
}
测试结果如下:
?
注意:为防止恶意操作,一般模板方法都加上 final 关键词。
在上述的案例中,在现实生活中像取号和排队操作是不一定需要执行,比如一般在一般中如果是VIP的话那去办理业务一般是有独立的窗口,不需要去取号和排队的,因此,VIP的用户只需执行办理具体业务和离开银行即可。
我们可以引入模板方法模式中的 钩子方法,通过钩子方法返回的布尔值来决定是否需要执行模板方法中的某个操作。
钩子方法 的作用主要体现在以下几个方面:
提供默认行为: 钩子方法通常在抽象类中提供了一个默认的实现,这个默认实现可以在模板方法中被调用。如果具体子类选择不覆盖钩子方法,就会使用这个默认行为。这使得在不同的子类中可以有一些通用的行为。
允许选择性的行为扩展: 具体子类可以选择性地覆盖钩子方法,以添加或修改某些行为,以适应特定的需求。这为子类提供了一定的灵活性,使其能够自定义模板方法的部分行为,而不需要修改整个模板方法。
控制模板方法执行流程: 钩子方法的返回值通常被用于在模板方法中控制流程。例如,可以使用钩子方法返回的布尔值来决定是否执行模板方法中的某个步骤。这样,通过覆盖钩子方法,可以在不同的子类中控制模板方法的执行流程。
接下来,我们使用钩子方法对上述例子进行改造,具体实现类如下:
抽象类:
public abstract class AbstractClass {
//模板方法(定义基本方法的执行顺序)
public final void service() {
if (isVIP()) {
getNum();
doWait();
}
doService();
doExit();
}
//钩子方法
public boolean isVIP() {
return false;
}
//下面的方法都称为基本方法
//第一步:取号(一样的,所以直接实现)
public void getNum() {
System.out.println("取号");
}
//第二部:排队(一样的,所以直接实现)
public void doWait() {
System.out.println("排队");
}
//第三步:办理具体业务(不一样,由子类实现)
public abstract void doService();
//第四步:离开银行(一样的,所以直接实现)
public void doExit() {
System.out.println("离开银行");
}
}
存款业务类:
public class SaveMoney extends AbstractClass {
public void doService() {
System.out.println("办理存款业务");
}
//覆盖钩子方法
@Override
public boolean isVIP() {
return true;
}
}
取款业务类:
public class TakeMoney extends AbstractClass {
public void doService() {
System.out.println("办理取款业务");
}
}
客户端类:
public class client {
public static void main(String[] args) {
//办理存款业务
SaveMoney saveMoney = new SaveMoney();
saveMoney.service();
System.out.println("---------------");
//办理取款业务
TakeMoney takeMoney = new TakeMoney();
takeMoney.service();
}
}
测试结果:
优点:
缺点:
?
非常感谢您阅读到这里,如果这篇文章对您有帮助,希望能留下您的点赞👍 关注💖 分享👥 留言💬thanks!!!