系列文章目录
创建型模式 - 单例模式(一)
创建型模式 - 工厂模式(二)
创建型模式 - 原型模式(三)
创建型模式 - 建造者模式(四)
结构型模式 - 适配器模式(一)
结构型模式 - 桥接模式(二)
结构型模式 - 装饰器模式(三)
结构型模式 - 组合模式(四)
结构型模式 - 外观模式(五)
结构型模式 - 享元模式(六)
结构型模式 - 代理模式(七)
行为型模式 - 模板方法模式(一)
行为型模式 - 命令模式(二)
行为型模式 - 访问者模式(三)
行为型模式 - 迭代器模式(四)
行为型模式 - 观察者模式(五)
行为型模式 - 中介者模式(六)
行为型模式 - 备忘录模式(七)
行为型模式 - 解释器模式(八)
行为型模式 - 状态模式(九)
行为型模式 - 策略模式(十)
行为型模式 - 责任链模式(十一)
文章目录
前言
一、模板方法模式
1.1 模板方法模式介绍
- 模板方法(Template Method Pattern)模式:
- 又叫模板模式(Template Pattern),在一个抽象类公开定义了执行它的方法模板,它的子类可以按需重写方法实现,但调用将以抽象类中定义的方式进行即
父类定义算法骨架,某些实现放在子类
;
1.2 模板方法模式结构
- 抽象类/抽象模板(Abstract Class):
- 抽象模板类,负责给出一个算法的轮廓和骨架,它是由一个模板方法和若干个基本的方法构成;
- 模板方法:定义算法骨架,按某种顺序调用其包含的基本方法;
- 基本方法:是整个算法中的一个步骤;
- 具体子类/具体实现(Concrete Class):
- 实现抽象类中所定义的抽象方法和钩子方法;
二、实现
例子:
- 炒菜(开火-加菜-加盐-翻炒-出锅);
2.1 模板方法实现
package com.dozezz.designpattern.template;
/**
* 抽象模板
*/
public abstract class CookTemplate {
/**
* 定義算法:定義好了模板
* 父類可以實現某些步驟,劉關鍵給子類
*/
public void cook(){
heating();
addFood();
addSalt();
stirFry();
endCook();
}
/**
* 加熱
*/
public void heating(){
System.out.println("開火。。");
}
/**
* 加食材
*/
public abstract void addFood();
/**
* 加鹽
*/
public abstract void addSalt();
/**
* 翻炒
*/
public void stirFry(){
System.out.println("翻炒。。");
}
/**
* 出鍋
*/
public void endCook(){
System.out.println("出鍋。。");
}
}
package com.dozezz.designpattern.template;
/**
* 具体实现
*/
public class AutoCookMachine extends CookTemplate{
@Override
public void addFood() {
System.out.println("放牛肉丁。。。");
}
@Override
public void addSalt() {
System.out.println("加半勺鹽");
}
}
package com.dozezz.designpattern.template;
/**
* 主测试类
*/
public class ClientTest {
public static void main(String[] args) {
AutoCookMachine autoCookMachine = new AutoCookMachine();
autoCookMachine.cook();
}
}
2.2 模板方法的"钩子"方法
- 在模板方法模式的父类中,我们可以定义一个方法,它默认不做任何事情,子类可以视情况要不要覆盖它,该方法成为“钩子”;
package com.dozezz.designpattern.template;
/**
* 抽象模板
*/
public abstract class CookTemplate {
/**
* 定義算法:定義好了模板
* 父類可以實現某些步驟,劉關鍵給子類
*/
public void cook(){
heating();
addFood();
if(customizerCondiments()){
addCustomizerCondiments();
}
addSalt();
stirFry();
endCook();
}
/**
* 用户自定义步骤
*/
public abstract void addCustomizerCondiments();
public Boolean customizerCondiments() {
return Boolean.FALSE;
}
/**
* 加熱
*/
public void heating(){
System.out.println("開火。。");
}
/**
* 加食材
*/
public abstract void addFood();
/**
* 加鹽
*/
public abstract void addSalt();
/**
* 翻炒
*/
public void stirFry(){
System.out.println("翻炒。。");
}
/**
* 出鍋
*/
public void endCook(){
System.out.println("出鍋。。");
}
}
package com.dozezz.designpattern.template;
/**
* j具体实现
*/
public class AutoCookMachine extends CookTemplate{
@Override
public void addCustomizerCondiments() {
System.out.println("放調料。。。");
}
@Override
public Boolean customizerCondiments() {
return Boolean.TRUE;
}
@Override
public void addFood() {
System.out.println("放牛肉丁。。。");
}
@Override
public void addSalt() {
System.out.println("加半勺鹽");
}
}
package com.dozezz.designpattern.template;
/**
* 主测试类
*/
public class ClientTest {
public static void main(String[] args) {
AutoCookMachine autoCookMachine = new AutoCookMachine();
autoCookMachine.cook();
}
}
三、模板方法模式总结
3.1 模板方法的应用场景
算法的整体步骤是很固定,但其中个别部分易变时,这个时候可以使用模板方法模式,将容易变的部分抽象出来,供子类实现;
当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免重复代码:
- 要识别现有代码中的不同之处,并且将不同之处分离为新的操作;
- 用一个调用这些新的操作的模板方法来替换这些不同的代码;
当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样只允许在这些点进行扩展;
3.2 模板方法的注意细节
- 算法只存在于一个地方,也就是父类,容易修改。需要修改算法时,只要修改父类的模板方法或已经实现的某些步骤,子类就会继承这些修改;
- 实现了最大化代码复用,父类的模板方法和已实现的某些步骤被子类继承而直接使用;
- 即统一了算法,也提供了很大的灵活性,父类的模板方法确保了算法的结构保持不变,同时由子类提供部分步骤的实现。
- 每一个不同的实现都需要一个子类实现,导致类的个数增加,使得系统更加庞大;
- 一般模板方法都加上final关键字,防止子类重写模板方法;
四、参考文献
- http://c.biancheng.net/view/1376.html
- https://www.cnblogs.com/noteless/p/10178477.html
- https://www.bilibili.com/video/BV1G4411c7N4?p=54&spm_id_from=pageDriver