设计模式_1_模板方法模式

当在编写软件的过程中,对于某一个功能的实现,常有固定的操作结构及步骤,但对于不同需求细节而言,我们经常希望某些子步骤能够作出特有的改变,例如使用某些第三方库的功能时,我们希望能够在函数调用的过程中添加一些我们自己的需求。


在这种稳定的框架中,那么如何灵活应对各个子步骤的变化,或者后期的需求改变呢?这里我们就抛出本篇的设计模式:模版方法模式

先抛出定义:定义一个操作中的算法骨架**(稳定),而将算法的一些步骤延迟(变化)到子类中,使得子类可以不改变(复用)该算法结构的情况下重定义(override)**该算法的某些特定步骤。它是一种类行为型模式。

光通过定义是晦涩难懂的,下面我们通过具体的例子来理解:


假设我们使用如下的类来举例,以Library类代表第三方库,以Application代表我实际开发的需求, 如果在这样一个固定的框架中,我需要通过Lib的流程来策略选择具体实现的操作,那么他们之间的关系流程如下:
class Library{
public:
    bool step1(){
        //...
    }
    int step3(){
        //...
    }
    void step5(){
        //...
    }
};

class Application{
public:
    void step2(){
        //...
    }
    void step4(){
        //...
    }
};

int main(){
    Library* lib=new Library();
    Application* app=new Application();
	
	if(lib->step1())
        app->step2();
    for(int i=0,n=lib->step3();i<n;++i)
	    app->step4();
    app->step5();
	//delete...
}

简单来讲,上述的流程便是由程序库设定稳定部分,并由开发人员写出变化部分和程序主流程,这便是一种早绑定的实现方式,

什么是早绑定?

在上述例子里,Library一定是早于Application所实现的,这样开发人员才能应用到具体的Lib,一个后实现的方法来调用先实现的方法,或根据其结果来作出对应操作,这样的实例便是早绑定,这也是比较普遍的一种现象;

在面向对象语言出现后,晚绑定的方法便诞生了,即:一个 先实现的方法 来调用 后实现的方法,与前者恰好相反。

观察刚刚的方法,显而易见,step1和step3就是这个操作中的算法骨架(稳定部分),step2和step4便“应该”属于算法的一些步骤(变化的部分),之所以用引号,是因为上述的写法,step2和step4,甚至main流程并不属于Lib里,下面我们经过优化,来实现一个真正的复合模版方法设计模式的实例:

class Library{
public:
    void Run(){
        if(step1())
            step2();
        for(int i=0,n=step3();i<n;++i)
            step4();
        step5();
    }

    virtual ~Library(){}
protected:
    virtual void step2()=0;
    virtual void step4()=0; 
    bool step1(){
        //do something
    }
    int step3(){
        //do something
    }
    void step5(){
        //do something
    }
};

class Application:public Library{
public:
    virtual void step2(){
        //do something
    }
    virtual void step4(){
        //do something
    }
};

int main(){
    Library* app=new Application();
    app->Run();

    delete app;
}

在上述符合代码中,便是晚绑定的逻辑:程序库开发早于用户,但却将变化的具体细节交给用户来实现,我们所要做的也就仅有实现我们自己的Application类、重写对应的变化的操作并调用。

这种设计模式的特征特别明显并非常基础,在面向对象系统中有着大量的应用。它用最简洁的机制(虚函数的多态性)为很多应用程序框架提供了灵活的扩展,是代码复用方面的基本实现结构。除了可以灵活应对子步骤的变化外,“Don’t call me, let me call you(不要调用我,让我来调用你)”的反向控制结构是Template Method的典型应用。


模板方法模式的主要优点有:

  1. 它封装了不变部分,扩展可变部分。它把认为是不变部分的算法封装到父类中实现,而把可变部分算法由子类继承实现,便于子类继续扩展。
  2. 它在父类中提取了公共的部分代码,便于代码复用。
  3. 部分方法是由子类实现的,因此子类可以通过扩展方式增加相应的功能,符合开闭原则。

模板方法模式的主要缺点为:

  1. 对每个不同的实现都需要定义一个子类,这会导致类的个数增加,系统更加庞大,设计也更加抽象,间接地增加了系统实现的复杂度。
  2. 父类中的抽象方法由子类实现,子类执行的结果会影响父类的结果,这导致一种反向的控制结构,它提高了代码阅读的难度。
  3. 由于继承关系自身的缺点,如果父类添加新的抽象方法,则所有子类都要改一遍。

文章读到最后,可能会有人可能会问:如果极端的方向来讲,我们使用这种模式的前提是这个框架的整体是稳定的,如果他是不稳定的,或者其中的每一步都是不稳定的(每一个步骤都是虚函数),即这个软件体系结构的所有都不稳定,那这个模式还适合吗?
在回答这个问题之前,我们要先明确一个点:即所有设计模式的假设条件:必须有一个稳定点,但不能完全稳定
后者是很好理解d1,如果一个设计模式是完全稳定没有变化的,那么根本也就不需要用到这个设计模式,是没有意义的;
而对于前者来说,设计模式的最大作用,即在变化和稳定之间寻找隔离点,所以一个稳定的基础和非完全稳定的基础都是必不可少的

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值