模板方法模式:定义一个操作中的算法的框架,而将一些步骤延迟都子类中。使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤。
模板方法模式很简单,只是使用了Java的继承机制而已。
我们看一个例子:
在一线城市,有好多条地铁线路,但是其中并不是所有的地铁线路都是属于一家企业的。所以对应的地铁的闸机也是不一样的。
我们定义一个闸机抽象类、一个1号线的地铁闸机类,一个4号线的地铁闸机类
抽象闸机类(AbstractGate.java)
package template;
/**
* 抽象闸机类
*/
public abstract class AbstractGate {
/**
* 读取卡信息
*/
public abstract void readCard();
/**
* 验证卡信息
*/
public abstract void validCard();
/**
* 开闸门
*/
public abstract void openGate();
}
1号线闸机类(OneLineGate.java)
package template;
/**
* 1号线闸机
*/
public class OneLineGate extends AbstractGate{
@Override
public void readCard() {
System.out.println("1号线闸机读取卡信息");
}
@Override
public void validCard() {
System.out.println("1号线闸机验证卡信息");
}
@Override
public void openGate() {
System.out.println("1号线闸机开门");
}
/**
** 过闸机流程
*/
public void run(){
this.readCard();
this.validCard();
this.openGate();
}
}
4号线闸机类(FourLineGate.java)
package template;
/**
* 4号线闸机
*/
public class FourLineGate extends AbstractGate{
@Override
public void readCard() {
System.out.println("4号线闸机读取卡信息");
}
@Override
public void validCard() {
System.out.println("4号线闸机验证卡信息");
}
@Override
public void openGate() {
System.out.println("4号线闸机开门");
}
/**
** 过闸机流程
*/
public void run(){
this.readCard();
this.validCard();
this.openGate();
}
}
到此,我们发现1号线跟4号线的过闸机流程是一致的,所以,我们没必要在两个地方分别写,我们可以将其提取到闸机抽象类中。如下:
包含过闸机流程的闸机抽象类(AbstractGate.java)
package template;
/**
* 包含过闸机流程的闸机抽象类
*/
public abstract class AbstractGate {
/**
* 读取卡信息
*/
public abstract void readCard();
/**
* 验证卡信息
*/
public abstract void validCard();
/**
* 开闸门
*/
public abstract void openGate();
/**
** 过闸机流程
*/
public void run(){
this.readCard();
this.validCard();
this.openGate();
}
}
在这里我们将AbstractGate类中的readCard(读取卡信息)、validCard(验证卡信息)、openGate(开闸门)称之为基本方法,而run(过闸机流程)称之为模板方法。
package template;
public class Demo {
public static void main(String[] args) {
AbstractGate gate1 = new OneLineGate();
gate1.run();
System.out.println("---------------------");
AbstractGate gate4 = new FourLineGate();
gate4.run();
}
}
对应输出:
1号线闸机读取卡信息
1号线闸机验证卡信息
1号线闸机开门
4号线闸机读取卡信息
4号线闸机验证卡信息
4号线闸机开门
但是,现实中过闸机是没那么简单的。闸机可能在某些紧急情况下(如火灾、事故等,希望永远没有)需要直接通过,所以我们做如下改造,也可称之为对模板方法模式的扩展。
增加了钩子方法的闸机抽象类(AbstractGate.java)
package template;
/**
* 抽象闸机类
*/
public abstract class AbstractGate {
/**
* 读取卡、验证卡标示
*/
protected boolean checkFlag = true;
/**
* 读取卡信息
*/
public abstract void readCard();
/**
* 验证卡信息
*/
public abstract void validCard();
/**
* 开闸门
*/
public abstract void openGate();
/**
* 过闸机流程
*/
public void run(){
if(this.isCheckCard()){
this.readCard();
this.validCard();
}
this.openGate();
}
/**
* 钩子方法,这里可以是抽象方法,这样的话子类就要主动实现,如果这里是具体实现,则子类可以使用默认,不主动实现,但是也可以重写该方法,来达到控制过闸机流程
* @return
*/
public boolean isCheckCard(){
return this.checkFlag;
}
/**
* 设置读取卡、验证卡标示
*/
public void setCheckFlag(boolean flag){
this.checkFlag = flag;
}
}
我们看到该抽象类增加了钩子方法,用以控制过闸机流程,增加了读取卡、验证卡标示属性,以及设置该属性的具体方法。
package template;
public class Demo {
public static void main(String[] args) {
AbstractGate gate1 = new OneLineGate();
gate1.setCheckFlag(false);
gate1.run();
System.out.println("---------------------");
gate1.setCheckFlag(true);
gate1.run();
System.out.println("---------------------");
AbstractGate gate4 = new FourLineGate();
gate4.setCheckFlag(false);
gate4.run();
System.out.println("---------------------");
gate4.setCheckFlag(true);
gate4.run();
}
}
对应输出:
1号线闸机开门
1号线闸机读取卡信息
1号线闸机验证卡信息
1号线闸机开门
4号线闸机开门
4号线闸机读取卡信息
4号线闸机验证卡信息
4号线闸机开门
我们看到设置checkFlag为true时,闸机走正常的读取卡、验证卡、开闸门流程,当设置checkFlag为false时,直接开闸门了,由此通过钩子程序达到控制开闸门的流程的功能。