首先形象的理解什么是模板:
可以用英语作文中的模板来进行理解:
确定的部分就是框架,不确定的部分就是根据作文题目灵活进行发挥的内容,我们写作文的时候也是先构思好框架,再去往框架中填充根据具体题目临时发挥的内容,不确定的部分就可以看成框架中的空格,可以根据具体的问题去填,就相当于具体去实现了,实现的时候就把不确定的部分给确定了
模板方法设计模式概述:
当功能内部一部分实现是确定的(确定的部分就可以用模板来理解,比如英语作文的模板),一部分实现是不确定的。这时可以把不确定的部分暴露出去,让子类去实现。换句话说,在软件开发中实现一个算法时,整体步骤很固定、通用, 这些步骤已经在父类中写好了。但是某些部分易变,易变部分可以抽象出来(此类为抽象类),供不同子类实现,我们调的时候要是调父类中固定的方法,在这个方法中又去调用重写的方法,这就是一种模板模式。
让父类具有固定的结构
模板方法把大部分功能都写好了,不确定的部分暴露给我们,我们去继承,实现好以后调用流程化的功能,遇到之前的不确定部分调用的就是已经重写的部分
例子1:
package test01;
public class test {
public static void main(String[] args) {
Template t=new SubTemplate();//也可以写成SubTemplate t=new SubTemplate();
//我们是去显式地调用模板方法,而不是显式的调用重写的方法,只是模板方法中使用了我们重写的方法
//重写的回调方法不要显式的去调用
t.spendTime();//执行到code()时,因为这里实际上是this.code();this就是t,因为subTemplate对code进行了重写所以执行的是子类重写的code方法
} //子类重写父类的方法调用的肯定是子类的方法
}
//模板方法中很多东西都是确定的,里面只是有部分东西是不确定的,对于那些不确定的地方进行抽象,在子类中重写抽象方法,子类对象去调用固定方法,在方法中遇到的抽象部分就替换为子类已经重写好的部分
//稍微固定的结构为父类,里面有一些是固定的,比如有一个方法来计算某段代码执行所花费的时间,但测试哪段代码所花的时间是不确定的,因为不确定我们就写成一个抽象的
//在模板方法中,去调用code(),
abstract class Template{
//对于spendTime来说,他的整体的流程是确定的,只是某些部分是易变的
// spendTime()方法的作用:计算某段代码执行所花费的时间
public void spendTime() {
long start=System.currentTimeMillis();
code();//不确定的部分,或者说易变的的部分,这种叫做回调方法,也叫做钩子方法
long end=System.currentTimeMillis();
System.out.println("花费的时间为:"+(end-start));
}
public abstract void code();
}
class SubTemplate extends Template{
@Override
public void code() {
for(int i=2;i<=1000;i++) {
boolean isFlag=true;
for(int j=2;j<=Math.sqrt(i);j++) {
if(i%j==0) {
isFlag=false;
break;
}
}
if(isFlag) {
System.out.println(i);
}
}
}
}
例子2:
package test01;
public class test{
public static void main(String[] args) {
BankTemplateMethod btm = new DrawMoney();//在测试类中new子类对象
btm.process();//通过子类对象去调用process
BankTemplateMethod btm2 = new ManageMoney();
btm2.process();
}
}
abstract class BankTemplateMethod {
// 具体方法
public void takeNumber() {
System.out.println("取号排队");
}
//因为不同的人办理的业务不一样,所以要定义成抽象的,这种方法叫做钩子方法,也叫做回调方法
public abstract void transact(); // 办理具体的业务
public void evaluate() {
System.out.println("反馈评分");
}
// 模板方法,把基本操作组合到一起,子类一般不能重写,用final进行修饰
public final void process() {
this.takeNumber();
this.transact();// 像个钩子,具体执行时,挂哪个子类,就执行哪个子类的实现代码
this.evaluate();
}
}
//子类重写抽象方法
class DrawMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要取款");
}
}
//子类重写抽象方法
class ManageMoney extends BankTemplateMethod {
public void transact() {
System.out.println("我要理财");
}
}