模版方法(Template Method)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Alatebloomer/article/details/82657188

“组件协作”模式:

  • 现代软件专业分工之后的第一个结果是“框架与应用程序的划分”,“组件协作”模式通过晚期绑定,来实现框架与应用程序之间的松耦合,使二者之间协作时常用的模式。
  • 典型模式
    • Template Method
    • Strategy
    • Observer / Event

Template Method

定一个操作中的算法的骨架(稳定的),而将一些步骤延迟(容易变化的)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重新定义(Override覆写)该算法的某写特定步骤
——《设计模式(GoF)》

动机(Motivation)

  • 在软件构建过程中,对于某一项任务,它常常有稳定的整体操作结构,但各个子步骤却有很多改变的需求,或者由于固有的原因(比如框架与应用之间的关系)而无法和任务的整体结构同时实现。
  • 如何在确定稳定操作结构的前提下,来灵活应对各个子步骤的变化或者晚期实现需求?

例子:下面的伪码主要是有两个开发人员来构成的代码,分别是库开发人员和应用程序的开发人员。对于库的开发人员来说,已经开发完成了所需要功能的1、3、5三个步骤;而如果要实现这个完整功能,需要应用程序的开发人员实现其中的2和4这两步。同时,还需要应用程序的开发者,在使用的时候,依次来调用库和自己开发的这几个函数。

//程序库开发人员
class Library{
 
public:
    void Step1(){
        //...
    }
 
    void Step3(){
        //...
    }
 
    void Step5(){
        //...
    }
};
 
//应用程序开发人员
class Application{
public:
    bool Step2(){
        //...
    }
 
    void Step4(){
        //...
    }
};
 
int main()
{
    Library lib();
    Application app();
 
    lib.Step1();
 
    if (app.Step2()){
        lib.Step3();
    }
 
    for (int i = 0; i < 4; i++){
        app.Step4();
    }
 
    lib.Step5();
 
}


问题:

  1. 首先,对应用程序的开发人员来说,他需要自己开发其中的第二和第五步的函数的开发。对于应用程序的开发者来说,要求是比较高的,必须对库中的函数情况比较了解,重写的两个函数的难度也相对较大,对于函数整体执行流程也不被库函数的开发人员所控制。
  2. 最关键的问题,库开发人员和应用程序的开发人员所开发的内容的耦合度很高,彼此相互交织在一起,还需要由用开发人员来组织整体调用流程。未来程序的扩展性和可维护性的难度都比较大。

解决办法:

//程序库开发人员
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; //变化
};
 
//应用程序开发人员
class Application : public Library {
protected:
    virtual bool Step2(){
        //... 子类重写实现
    }
 
    virtual void Step4() {
        //... 子类重写实现
    }
};
 
int main()
    {
        Library* pLib=new Application();
        lib->Run();
 
        delete pLib;
    }
}



在第一种实现中Application调用Library,是一种早绑定。而在第二种方法中,Library调用Application,实现的是一种晚绑定。耦合性相对也很低,库的开发人员完全不需要管应用开发人员的开发情况,可以独立完成自己的开发任务。对于应用程序的开发人员来说,只需要用简单的应用即可,而不需要考虑其中具体的实现过程。所以这样的设计方法的耦合性较低。

注意:对于Template Method来说,有一个前提,就是Run()方法必须要是稳定的。如果Run()不稳定,那么没有一个稳定的软件的骨架,就不存在这样一种设计模式。假定,所有方式都是稳定,那么其实也没有必要使用设计模式。

要点总结:

  1. Template Method是一种非常基础性的设计模式,在面向对象的系统中,有着大量的应用。他用最简洁的机制(虚函数的多态性)为很多应用程序的框架提供了灵活的扩展点,是代码复用方面的基本实现结构。
  2. 除了可以灵活对应子步骤的变化外,“不要调用我,让我来调用你”的反向控制结构是Template Method的典型应用。
  3. 在具体实现方面,被Template Method调用的虚方法可以具有实现,也可以没有任何实现(抽象方法、纯虚方法),一般推荐将他们设置为protected方法。

猜你喜欢

转载自blog.csdn.net/Alatebloomer/article/details/82657188