目录
1.定义
2.模板方法模式的优点
a.封装不变部分,扩展可变部分;
b.提取公共部分代码,便于维护;
c.行为由父类控制,子类实现。
3.模板方法模式的缺点
按照我们的设计习惯,抽象类负责声明最抽象、最一般的事物属性和方法,实现类完成具体的事物属性和方法。但是模板方法模式却颠倒了,抽象类定义了部分抽象方法,由子类实现,子类执行的结果影响了父类的结果,也就是子类对父类产生了影响,这在复杂的项目 中,会带来代码阅读的难度,而且也会让新手产生不适感。(引用于设计模式之禅)
4.模板方法模式的通用类图
5.模板方法模式的简单实现
5-1.创建模板抽象类WarModel
package com.alex.design.templatePattern.war;
/**
* 战争模板的抽象类
*/
public abstract class WarModel {
/**
* 开打(基本方法)
*/
protected abstract void start();
/**
* 伤亡(基本方法)
*/
protected abstract void casualty();
/**
* 停战(基本方法)
*/
protected abstract void stop();
/**
* 战争过程(模板方法,建议加上final关键字,防止调用方覆盖了该方法)
*/
protected final void run(){
this.start();
this.casualty();
this.stop();
}
}
5-2.创建战争模板实现类(秦军)QinWarModel
package com.alex.design.templatePattern.war;
/**
* 战争模板实现类(秦军)
*/
public class QinWarModel extends WarModel {
@Override
protected void start() {
System.out.println("秦军出击");
}
@Override
protected void casualty() {
System.out.println("秦军开始产生伤亡了");
}
@Override
protected void stop() {
System.out.println("秦军退军");
}
}
5-3.创建战争模板实现类(汉军)HanWarModel
package com.alex.design.templatePattern.war;
/**
* 战争模板实现类(汉军)
*/
public class HanWarModel extends WarModel {
@Override
protected void start() {
System.out.println("汉军出击");
}
@Override
protected void casualty() {
System.out.println("汉军开始产生伤亡了");
}
@Override
protected void stop() {
System.out.println("汉军退军");
}
}
5-4.创建客户端WarClient
package com.alex.design.templatePattern.war;
/**
* 客户端
*/
public class WarClient {
public static void main(String[] args) {
WarModel qin = new QinWarModel();
qin.run();
System.out.println("---------------------");
WarModel han = new HanWarModel();
han.run();
}
}
6. 模板方法模式的使用场景
● 多个子类有公有的方法,并且逻辑基本相同时。● 重要、复杂的算法,可以把核心算法设计为模板方法,周边的相关细节功能则由各个子类实现。● 重构时,模板方法模式是一个经常使用的模式,把相同的代码抽取到父类中,然后通过钩子函数(见 “ 模板方法模式的扩展 ”)约束其行为。 (引用于设计模式之禅)
7.模板方法模式的扩展
7-1.场景如下,通过刚刚的例子可以发现,秦军和汉军两个实现类都是继承于战争模板抽象类的,所以流程都是一样的,那么如果现在要是汉军不受到伤亡,应该怎么做呢?可以借助钩子方法,然后通过实现类控制是否产生伤亡,具体做法如下:
7-2.调整WarModel了,新增钩子方法isCasualty:
package com.alex.design.templatePattern.war;
/**
* 战争模板的抽象类
*/
public abstract class WarModel {
/**
* 开打(基本方法)
*/
protected abstract void start();
/**
* 伤亡(基本方法)
*/
protected abstract void casualty();
/**
* 停战(基本方法)
*/
protected abstract void stop();
/**
* 战争过程(模板方法,建议加上final关键字,防止调用方覆盖了该方法)
*/
protected final void run() {
this.start();
if (isCasualty()) {
this.casualty();
}
this.stop();
}
//钩子方法,默认有伤亡
protected Boolean isCasualty() {
return true;
}
}
7-3.调整实现类QinWarModel和HanWarModel,继承父类的钩子方法,并对其进行赋值:
package com.alex.design.templatePattern.war;
/**
* 战争模板实现类(秦军)
*/
public class QinWarModel extends WarModel {
private boolean flag = true; //有伤亡
@Override
protected void start() {
System.out.println("秦军出击");
}
@Override
protected void casualty() {
System.out.println("秦军开始产生伤亡了");
}
@Override
protected void stop() {
System.out.println("秦军退军");
}
@Override
protected Boolean isCasualty() {
return this.flag;
}
//要不要伤亡,是由客户来决定的
public void setCasualty(boolean flag) {
this.flag = flag;
}
}
package com.alex.design.templatePattern.war;
/**
* 战争模板实现类(汉军)
*/
public class HanWarModel extends WarModel {
private boolean flag = true; //有伤亡
@Override
protected void start() {
System.out.println("汉军出击");
}
@Override
protected void casualty() {
System.out.println("汉军开始产生伤亡了");
}
@Override
protected void stop() {
System.out.println("汉军退军");
}
@Override
protected Boolean isCasualty() {
return this.flag;
}
//要不要伤亡,是由客户来决定的
public void setCasualty(boolean flag) {
this.flag = flag;
}
}
7-4.客户端WarClient的调整,实现对是否有伤亡的控制:
package com.alex.design.templatePattern.war;
/**
* 客户端
*/
public class WarClient {
public static void main(String[] args) {
QinWarModel qin = new QinWarModel();
qin.setCasualty(true);
qin.run();
System.out.println("---------------------");
HanWarModel han = new HanWarModel();
han.setCasualty(false);
han.run();
}
}
7-5.效果截图如下: