侧边栏壁纸
博主头像
LittleAO的学习小站 博主等级

在知识的沙漠寻找绿洲

  • 累计撰写 125 篇文章
  • 累计创建 27 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

设计模式之 模板方法(Template Method)模式

LittleAO
2024-09-27 / 0 评论 / 0 点赞 / 14 阅读 / 0 字
温馨提示:
本文最后更新于2024-09-27,若内容或图片失效,请留言反馈。 部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

介绍

模板方法模式应用比较广泛,可以说它是继承应用的一个基础。有一些情况下,我们实现各种相似的类。不用继承的笨办法就是为分别定义不同的类。这样做的成本比较大,一个简单的办法是,我们可以把不同类中相同部分剥离出来声明一个基类,然后分别继承再实现。这样做确实不错,但是一定程度上增加了耦合。

模板方法模式需要我们创建一个模板(基类),然后根据这个模板生成不同的实现。具体点来说,就是不同的类要继承一个抽象类,这个抽象类中定义了不同的接口。派生类需要实现这些接口。

实现

给模板方法模式下一个具体的定义:父类中定义处理流程的框架,子类中实现具体处理

UML图如下,图源《图解设计模式》:

需求

现在有如下需求:在控制台中输出文本,输出规则是:

  1. 第一行输出现在的类名

  2. 第二到六行输出类中的文本

  3. 第七行输出现在的类名+end

要求实现两个这样的类,分别处理string和char。

实现模板

看到这个需求,发现流程处理是一样的,只是数据类型不一样。我们可以先定义一个抽象类,其中的display函数包含了处理的流程:

class AbstractDisplay {
protected:
    virtual void open() = 0;
    virtual void print() = 0;
    virtual void end() = 0;

public:
    // 处理流程
    void display() {
        open();
        for (int i = 0; i < 5; ++i) {
            print();
        }
        end();
    }
};

模板中我们定义了接口和处理的流程。接下来我们需要在子类中实现。

具体实现

class CharDisplay : public AbstractDisplay {
public:
    CharDisplay(char c) : c(c) {}

protected:
    void open() override {
        std::cout << "CharDisplay" << std::endl;
    }

    void print() override {
        std::cout << c << std::endl;
    }

    void end() override {
        std::cout << "CharDisplay end" << std::endl;
    }
private:
    char c;
};

class StringDisplay : public AbstractDisplay {
public:
    StringDisplay(std::string c) : c(c) {}

protected:
    void open() override {
        std::cout << "StringDisplay" << std::endl;
    }

    void print() override {
        std::cout << c << std::endl;
    }

    void end() override {
        std::cout << "StringDisplay end" << std::endl;
    }
private:
    std::string c;
};

子类中我们无需关心业务的处理流程是怎样,只需要将基类中定义的接口实现即可。

尝试运行

在main函数实例化这些类,并调用display方法,结果满足需求。

int main()
{
    CharDisplay obj1('a');
    StringDisplay obj2("hello");
    obj1.display();
    obj2.display();
}

输出:

CharDisplay
a
a
a
a
a
CharDisplay end
StringDisplay
hello
hello
hello
hello
hello
StringDisplay end

扩展

C++中有没有更加便捷的方式实现上面的需求呢?答案是类模板。

template<typename T>
class GeneralDisplay
{
public:
    GeneralDisplay<T>(T val) : val(val) {}

    void display() {
        open();
        for (int i = 0; i < 5; ++i) {
            print();
        }
        end();
    }

private:
    T val;
    void open() {
        std::cout << "GeneralDisplay" << std::endl;
    }

    void print() {
        std::cout << val << std::endl;
    }

    void end() {
        std::cout << "GeneralDisplay end" << std::endl;
    }
};

int main()
{
    GeneralDisplay<std::string> obj("hello");
    obj.display();
}

0

评论区