设计模式(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]设计模式读书笔记—–模板方法模式

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

Golang 常见问题

1. Golang的特点和发起目的 Golang的特点以及要解决的问题概括起来就是三点: 1. concurrent : 多核 解决方式-> 语言层级并发, ...

3716
来自专栏胖胖的专栏

使用 trie 树实现简单的中文分词

导语:工作中偶尔遇到需要对中文进行分词的情况,不要求非常高的精确度和语境符合度,仅是为了统计某些词出现的热度。本文提供了一种简单易行的中文分词方法。 工作中,偶...

8575
来自专栏沈唁志

BC数学函数:PHP处理有关钱数等浮点数计算时高精确度函数库

在商城类的项目当中,避免不了钱数的计算,也就会出现所谓的浮点数精度问题,前两天阅文的小哥哥面试我的时候就问到了这个,Mysql怎么去存钱数?PHP又该怎么处理浮...

1012
来自专栏蓝天

Cuckoo Hash和多级Hash的粗浅认识

通过对Cuckoo Hash、多级Hash和BloomFilter的粗浅了解,感觉它们三者存在类似之处,算是近亲(暂且把普通的Hash称作远亲)。

900
来自专栏JadePeng的技术博客

知识图谱学习笔记(1)

RDF(Resource Description Framework),即资源描述框架,其本质是一个数据模型(Data Model)。它提供了一个统一的标准,用...

1870
来自专栏韩伟的专栏

基于对象和面向对象

“基于对象”是“面向对象”一次动态化变迁,它依赖于现代语言的动态特性,让方法和属性统一起来;用组合取代继承;以函数对象查找取代多态的方法调用。这些变化让面向对象...

1.4K0
来自专栏JadePeng的技术博客

知识图谱学习笔记(1)

4025
来自专栏青玉伏案

代码重构(四):条件表达式重构规则

继续更新有关重构的博客,前三篇是关于类、函数和数据的重构的博客,内容还算比较充实吧。今天继续更新,本篇博客的主题是关于条件表达式的重构规则。有时候在实现比较复杂...

2019
来自专栏aCloudDeveloper

python学习总结

最近经学长介绍学习python,为研究生做研究做准备,python对于科学计算有着很高的效率,对于科研人员当然是有着很强的诱惑,虽然我还没真正用它,但从整个学习...

2595
来自专栏Python小屋

微课系列(四):Python中map对象的几种用法和注意事项

在Python中,map、filter、enumerate、zip、reversed等对象除了惰性求值之外,还有个共同的特点是“其中的元素只能使用一次”,这一点...

842

扫码关注云+社区

领取腾讯云代金券