[设计模式] 设计模式课程(二)-- 模板模式

场景

  • 动机/场景:软件构建过程中,对某项任务常常有稳定的整体操作结构,但各个子步骤有很多改变的需求,或者由于固有原因(如框架与应用之间的关系)而无法和任务的整体结构同时实现
  • 需求:如何在确定稳定操作的前提下,灵活应对各个子步骤的变化或晚期实现需求?
  • 属于组件协作类
  • 背景:现代软件分工后第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合

原代码

template1_lib.cpp

 1 //应用程序开发人员
 2 class Application{
 3 public:
 4     bool Step2(){
 5         //...
 6     }
 7 
 8     void Step4(){
 9         //...
10     }
11 };
12 
13 int main()
14 {
15     Library lib();
16     Application app();
17 
18     lib.Step1();
19 
20     if (app.Step2()){
21         lib.Step3();
22     }
23 
24     for (int i = 0; i < 4; i++){
25         app.Step4();
26     }
27 
28     lib.Step5();
29 
30 }
View Code

template1_app.cpp

 1 //程序库开发人员
 2 class Library{
 3 
 4 public:
 5     void Step1(){
 6         //...
 7     }
 8 
 9     void Step3(){
10         //...
11     }
12 
13     void Step5(){
14         //...
15     }
16 };
View Code
  • 程序库开发人员实现Step1(),Step3(),Step5()
  • 应用开发人员实现Step2(),Step4()及应用程序主流程
  • 早绑定:应用调用库(库写的早,应用写的晚)
  • 用了面向对象语言,但设计思维是结构化的
  • 早期C语言开发常用流程,应用开发人员要自己写主流程

重构后

template2_lib.cpp

 1 //程序库开发人员
 2 class Library{
 3 public:
 4     //稳定 template method
 5     void Run(){
 6         
 7         Step1();
 8 
 9         if (Step2()) { //支持变化 ==> 虚函数的多态调用
10             Step3(); 
11         }
12 
13         for (int i = 0; i < 4; i++){
14             Step4(); //支持变化 ==> 虚函数的多态调用
15         }
16 
17         Step5();
18 
19     }
20     virtual ~Library(){ }
21 
22 protected:
23     
24     void Step1() { //稳定
25         //.....
26     }
27     void Step3() {//稳定
28         //.....
29     }
30     void Step5() { //稳定
31         //.....
32     }
33 
34     virtual bool Step2() = 0;//变化
35     virtual void Step4() =0; //变化
36 };
View Code

template2_app.cpp

 1 //应用程序开发人员
 2 class Application : public Library {
 3 protected:
 4     virtual bool Step2(){
 5         //... 子类重写实现
 6     }
 7 
 8     virtual void Step4() {
 9         //... 子类重写实现
10     }
11 };
12 
13 int main()
14     {
15         Library* pLib=new Application();
16         lib->Run();
17 
18         delete pLib;
19     }
20 }
View Code
  • 程序库开发人员实现Step1(),Step3(),Step5()及应用程序主流程,预留Step2(),Step4()给应用开发人员实现
  • 应用开发人员实现Step2(),Step4()
  • 多态指针(声明类型和实际类型不一致,按虚函数的动态绑定规则调用)
  • 基类的虚构函数写成虚函数
  • 晚绑定:库调用应用(框架开发指导思想)
  • 稳定中有变化,稳定的代码写成普通函数,变化的写成虚函数
  • 面向对象时代,绝大多数软件框架都有模板,应用开发人员不用写主流程(好处在于省事,弊端在于无法看清全局)

细节

  • Run()是一个模板(稳定),但稳定中有变化,变化的部分写成虚函数
  • 基类的虚函数写成虚函数,以调用子类的虚构函数
  • 原代码是早期软件开发(结构化程序设计)经常采用的方式,重构后是现代软件开发(面向对象程序设计)经常采用的方式
  • 定义一个操作中的算法的稳定骨架,而将一些变化步骤延迟到子类中,使得子类可以复用一个算法的结构或重写该算法的某些特定步骤
  • 采用简洁的机制(虚函数的多态性),为应用程序框架提供灵活的扩展点,使代码复用得以实现
  • 缺点:假定了Run()是稳定的
  • 如果一个程序是完全稳定或完全变化的,则任何设计模式都没有作用
  • 设计模式的关键:在变化和稳定之间寻找隔离点,分离他们,从而管理变化
  • 把变化像兔子一样关在笼子里,不让它污染整个房间
  • 反向控制(IOC):“不要调用我,让我来调用你”
  • UML图:红色是稳定部分,蓝色是变化部分
  • 建议把虚函数声明为protected
  • 其他晚绑定机制:C中的函数指针(虚函数背后也是函数指针)

[设计模式] 设计模式课程(二)-- 模板模式_第1张图片

 

你可能感兴趣的:([设计模式] 设计模式课程(二)-- 模板模式)