设计模式(11)——模板方法模式(Template Method Pattern,行为型)

1.概述

使用设计模式可以提高代码的可复用性、可扩充性和可维护性。

模板方法模式(Template Method Pattern)属行为型,在一个方法中定义一个算法骨架,而将一些步骤延迟到子类中,使子类可以不改变算法结构即可重定义算法的某些特定步骤。

模版方法模式结构图:
这里写图片描述

AbstractClass:实现了模板方法,定义了算法骨架。
ConcreteClass:实现抽象类中的抽象方法,完成完整的算法。

2.模板方法模式简单实现

我们仍来举一个武侠的例子。

一个武侠要战斗的时候,也有一套固定的模式,那就是运行内功、开通经脉、准备武器和使用招式。者一套固定模式可是为算法骨架,我们把这些用代码表示就是:

class AbstractSwordsman {
public:
    void fighting(){  
        //运行内功,抽象方法
        neigong();
        //调整经脉,具体方法
        meridian();
        //如果有武器则准备武器
        if (hasWeapons()) {
            weapons();
        }
        //使用招式
        moves();
        //钩子方法
        hook();//用于判断是否在算法骨架中是否执行某一算法
    }
protected:
    virtual void neigong() = 0;
    virtual void weapons() = 0;
    virtual void moves() = 0;
    virtual void meridian() {
        cout << "开通正经与奇经" << endl;
    }

    //是否有武器,默认是有武器的,钩子方法
    virtual bool hasWeapons() {
        return true;
    }
    //钩子方法实现为空
    virtual void hook(){}
};

需要注意的是这个抽象类包含了三种类型的方法,分别是抽象方法、具体方法和钩子方法。

抽象方法是交由子类去实现,具体方法则在父类实现了子类公共的方法实现,在上面的例子就是武侠开通经脉的方式都一样,所以就在具体方法中实现。钩子方法则分为两类,第一类是hook(),它有一个空实现的方法,子类可以视情况来决定是否要覆盖它;第二类则是hasWeapons(),这类钩子方法的返回类型通常是bool类型的,一般用于对某个条件进行判断,如果条件满足则执行某一步骤,否则将不执行。

定义具体实现类。本文就拿张无忌、张三丰来作为例子。

张无忌没有武器,所以hasWeapons()这个钩子方法返回false,这样就不会使用weapons方法了。

class ZhangWuJi:public AbstractSwordsman {
protected:
    //@Override
    void neigong() {
        cout << "运行九阳神功" << endl;
    }

    //@Override
    void weapons(){} //实现为空

    //@Override
    void moves() {
        cout << "使用招式乾坤大挪移"<<endl;
    }

    //@Override
    bool hasWeapons() {
        return false;
    }
};

最后张三丰突然肚子不舒服所以就实现了钩子方法hook。

class ZhangSanFeng:public AbstractSwordsman{
protected:
    //@Override
    void neigong() {
        cout << "运行纯阳无极功"<<endl;
    }

    //@Override
    void weapons() {
        cout << "使用真武剑"<<endl;
    }

    //@Override
    void moves() {
        cout << "使用招式神门十三剑"<<endl;
    }

    void hook() {
        cout << "突然肚子不舒服,老夫先去趟厕所"<<endl;
    }
};

客户端调用:

#include <iostream>
using namespace std;

int main() {
    ZhangWuJi wuji;
    wuji.fighting();
    cout << "-----------分割线----------" << endl;
    ZhangSanFeng sanfeng;
    sanfeng.fighting();
}

程序运行结果:

运行九阳神功
开通正经与奇经
使用招式乾坤大挪移
-----------分割线----------
运行纯阳无极功
开通正经与奇经
使用真武剑
使用招式神门十三剑
突然肚子不舒服,老夫先去趟厕所

3.模版方法模式的使用场景和优缺点

应用场景:
(1)各子类中公共的行为应被提取出来并集中到一个公共父类中以避免代码重复。
(2)面对重要复杂的算法,可以把核心算法设计为模版方法,周边相关细节功能交由各个子类实现。
(3)需要通过子类来决定父类算法中某个步骤是否执行,实现子类对父类的反向控制。

优点
(1)模板方法模式通过把不变的行为搬移到基类,去除了子类中的重复代码。
(2)子类实现算法的某些细节,有助于算法的扩展。

缺点:
每个不同的实现都需要定义一个子类,这会导致类的个数的增加,设计也更加抽象,但是更加符合“单一职责原则”,使得类的内聚性得以提高。

4.小结

(1)模板方法模式定义了算法的步骤,将这些步骤的实现延迟到了子类。

(2)模板方法模式为我们提供了一种代码复用的重要技巧。

(3)模板方法模式的抽象类可以定义抽象方法、具体方法和钩子方法。钩子的作用:
(3.1)作为可选内容,子类可以重写或者置之不理;
(3.2)让子类有机会对模板方法中即将发生的或者已经发生的步骤做出反应;
(3.3)作为控制条件,使得子类可以影响到抽象类中的算法流程。

(4)模板方法模式应用了好莱坞原则
”别打电话给我们,我们会打电话给你。“在好莱坞,把简历递交给演艺公司后只能静静等待,由演艺公司对整个娱乐项完全控制,演员只能被动式的接受公司的差使。应用到OO设计中,好莱坞原则指别调用我们,我们会调用你。低层不要调用高层,只有高层才会去调用低层。低层只管去实现具体方法,高层组件会决定什么时候和怎样使用这些低层组件。

依赖倒置原则教我们尽量避免使用具体类,多使用抽象。而好莱坞原则是在创建框架或组件上的一种技巧,好让低层组件能够被挂钩进到系统中,而又不让高层组件件依赖低层组件。两者的目标都是在于解耦,依赖倒置原则更加注重如何在设计中避免依赖。


参考文献

[1]设计模式(九)模版方法模式
[2]Head First 设计模式(中文版):275-311
[3]设计模式读书笔记—–模板方法模式

©️2020 CSDN 皮肤主题: 编程工作室 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值