1. 模式分类
从目的来看:
创建型模式
结构性模式
行为型模式
从范围来看:
类模式处理类与子类的静态关系。
对象模式处理对象间的动态关系。
从封装变化角度对模式分类:
组件协作:
Template Method
Strategy
Observer/Event
单一职责:
Decorator
Bridge
对象创建:
Factory Method
Abstact Factory
Prototype
Builder
对象性能:
Singleton
Flyweight
接口隔离:
Facade
Proxy
Mediator
Adapter
状态变化:
Memento
State
数据结构:
Composite
Iterator
Chain of
Resposibility
行为变化:
Command
Visitor
领域问题:
Interpreter
2. 重构获得模式 Refactoring to Patterns
面向对象设计模式是“好的面向对象设计”,所谓“好的面向对象设计”指的是那些可以满足“应对变化,提高复用”的设计。
现代软件设计的特征是“需求的频繁变化”。设计模式的要点在于“寻找变化点,然后在变化点处应用设计模式,从而来更好的应对需求的变化”。“什么时候、什么地点应用设计模式”比“理解设计模式结构本身”更为重要。
设计模式的应用不宜先入为主,一上来就是用设计模式是对设计模式最大误用。没有一步到位的设计模式。敏捷软件开发提倡的是“Refactoring to Patterns”是目前公认的最好的设计模式的方法。
3. 重构关键技法
静态-->动态
早绑定-->晚绑定
继承-->组合
编译时依赖-->运行时依赖
紧耦合-->松耦合
4. “组件协作”模式
现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚绑定,来实现框架与应用之间的松耦合,是两者之间协作时常用的模式。
经典模式:
Template Method
Strategy
Observer/Event
5. Template Method的动机
在软件构建过程中,对于某一项任务,他常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
如何在确定稳定操作结构的前提下,来灵活应对各个子步骤化的变化或者晚期实现需求?
6.代码
template1_lib.h文件内容
1 //程序库开发人员 2 3 //如果在实际的项目中,方法应该在相应的cpp文件中实现 4 class Library 5 { 6 public: 7 8 void Step1() 9 { 10 //... 11 } 12 13 void Step3() 14 { 15 //... 16 } 17 18 void Step5() 19 { 20 //... 21 } 22 };
template1_app.h
1 #pragma once 2 3 //应用开发人员 4 5 //如果在实际的项目中,方法应该在相应的cpp文件中实现 6 class Application 7 { 8 public: 9 bool Step2() 10 { 11 //... 12 } 13 14 void Step4() 15 { 16 //... 17 } 18 };
Main1.cpp
1 //应用程序开发人员 2 3 #include "template1_lib.h" 4 5 #include "template1_app.h" 6 7 int main() 8 { 9 Library lib; 10 Application app; 11 12 lib.Step1(); 13 if (app.Step2()) 14 { 15 lib.Step3(); 16 } 17 18 for (int i = 0; i < 4; i++) 19 { 20 app.Step4(); 21 } 22 23 lib.Step5(); 24 }
7. 利用Template Method设计模式修改后的代码
template2_lib.h
#pragma once //程序库开发人员 //如果在实际的项目中,方法应该在相应的cpp文件中实现 class Library { public: //稳定template method void Run() { Step1(); if (Step2()) //支持变化===》虚函数的多态调用 { Step3(); } for (int i = 0; i < 4; i++) { Step4(); //支持变化===》虚函数的多态调用 } Step5(); } virtual ~Library() //虚的析构函数 { //... } protected: void Step1() //稳定 { //... } void Step3() //稳定 { //... } void Step5() //稳定 { //... } virtual bool Step2() = 0; //变化 virtual void Step4() = 0; //变化 };
template2_app.h
#pragma once #include "template2_lib.h" class Application :public Library { protected: virtual bool Step2() { //...子类重写实现 } virtual void Step4() { //...子类重写实现 } };
Main2.cpp
#include "template2_lib.h" #include "template2_app.h" int main() { Library* pLib = new Application(); pLib->Run(); delete pLib; }
8. 图
9. Template Method模式定义
定义一个操作中的算法的骨架(稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override重写)该算法的某些特定步骤。稳定中有变化。当整个算法的骨架不稳定时,就不再适合Template Method。
10. 结构
11. 要点总结
Template Method模式是一种非常基础性的设计模式,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态调用)为很多应用程序框架提供了灵活的扩展点,是代码复用方面基本的实现结构。
除了可以灵活应对子步骤变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用场景。
在具体实现方面,被Template Method调用的虚函数方法可以实现,也可以没有任何实现(抽象方法、纯虚方法),一般推荐把它们设置为protected方法。
子类虚函数的晚绑定的实现机制就是虚函数表中挂了一个函数指针来实现的。