模板方法模式
GOF-23 模式分类
- 从目的来看
- 创建型(Creational)模式:将对象的创建工作延迟到子类或者其它对象,从而应对需求变化为对象创建时具体类型实现引来的冲击
- 结构型(Structural)模式:通过类继承或者对象组合获得更灵活的结构,从而应对需求变化为对象的结构带来的冲击
- 行为型(Behavioral)模式:通过类继承或者对象组合来划分类与对象间的职责,从而应对需求变化为多个交互对象带来的冲击
- 从范围来看(实现手段)
- 类模式:处理类与子类的静态关系,偏重继承方案
- 对象模式:处理对象间的动态关系,偏重组合方案
从封装变化角度对模式进行分类
- 组件协作
- 模板方法模式(Template)
- 策略模式(Strategy)
- 观察者/事件模式(Observer/Event)
- 单一职责
- 装饰模式(Decorator)
- 桥接模式(Bridge)
- 对象创建
- 工厂方法模式(Factory Method)
- 抽象工厂模式(Abstract Factory)
- 原型模式(Prototype)
- 构建器模式(Builder)
- 对象性能
- 单例模式(Singleton)
- 享元模式(Flyweight)
- 接口隔离
- 门面模式(Facade)
- 代理模式(Proxy)
- 中介者模式(Mediator)
- 适配器模式(Adapter)
- 状态变化
- 备忘录模式(Memento)
- 状态模式(State)
- 数据结构
- 组合模式(Composite)
- 迭代器模式(Iterator)
- 职责链模式(Chain of Responsibility)
- 行为变化
- 命令模式(Command)
- 访问器模式(Visitor)
- 领域问题
- 解析器模式(Interpreter)
重构获得模式(Refactoring to Patterns)
- 面向对象设计模式是“好的面向对象设计”,所谓“好的面向对象设计”是指那些可以满足“应对变化,提高复用”的设计
- 现代软件设计的特征是“需求的频繁变化”。设计模式的要点是“寻找变化点,然后在变化点处应用设计模式,从而来更好地应对需求的变化”,“什么时候、什么地点应用设计模式”比“理解设计模式结构本身”更为重要
- 设计模式的应用不宜先入为主,一上来就使用设计模式是对设计模式最大的误用。没有一步到位的设计模式。敏捷软件开发实践提倡的“Refactoring to Patterns”是目前公认的最好的使用设计模式的方法
图书推荐
《重构:改善既有代码的设计》
《重构与模式》
重构关键技法
- 静态 ==> 动态
- 早绑定 ==> 晚绑定
- 继承 ==> 组合
- 编译时依赖 ==> 运行时依赖
- 紧耦合 ==> 松耦合
“组件协作”模式
- 现代软件专业分工后的第一个结果是“框架与应用程序的划分”,“组件协作模式”通过晚期绑定,来实现框架与应用程序之间的松耦合,是二者之间协作时常用的模式
- 典型模型:
- 模板方法模式(Template)
- 策略模式(Strategy)
- 观察者/事件模式(Observer/Event)
模板方法模式(Template Method)
动机(Motivation)
- 在软件构建过程中,对于某一项任务,他常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或由于固有的原因(比如说框架和应用之间的关系)而无法和任务整体结构同时实现
- 如何在确定稳定操作结构的前提之下,来灵活应对各个子步骤的变化或者晚期实现需求?
结构化软件设计流程
面向对象软件设计流程
早绑定与晚绑定
模式定义
定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。模板方法使得子类可以不改变(复用)一个算法的结构即可以重定义(override重定义)该算法的某些特定步骤
设计模式最大的作用就是在变化和稳定中间寻找隔离点,然后分离它们,从而来管理变化
结构(Structure)
要点总结
- 模板方法模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。他用最简洁的机制(虚方法的多态性)为很多应用程序框架提供了灵活的扩展点,是代码复用方面的基本实现结构
- 除了可以灵活应对子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是模板方法的典型应用
- 具体实现方面,被模板方法调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),但一般推荐将它们设置为protected方法
源码示例
// 父类
public abstract class FrameworkServlet extends HttpServletBean implements ApplicationContextAware {
/**
* Callback that receives refresh events from this servlet's WebApplicationContext.
* <p>The default implementation calls {@link #onRefresh},
* triggering a refresh of this servlet's context-dependent state.
* @param event the incoming ApplicationContext event
*/
public void onApplicationEvent(ContextRefreshedEvent event) {
this.refreshEventReceived = true;
synchronized (this.onRefreshMonitor) {
onRefresh(event.getApplicationContext());
}
}
/**
* Template method which can be overridden to add servlet-specific refresh work.
* Called after successful context refresh.
* <p>This implementation is empty.
* @param context the current WebApplicationContext
* @see #refresh()
*/
protected void onRefresh(ApplicationContext context) {
// For subclasses: do nothing by default.
}
}
// 子类
public class DispatcherServlet extends FrameworkServlet {
/**
* This implementation calls {@link #initStrategies}.
*/
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
}