模板模式 Template pattern 实例与分析

设计模式均整理自李建忠老师的设计模式入门课

模板模式定义

定义一个操作中的算法的骨架 (稳定),而将一些步骤延迟(变化)到子类中。Template Method使得子类可以不改变(复用)一个算法的结构即可重定义(override 重写)该算法的某些特定步骤。

动机

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

模版模式的优缺点

优点

  • 封装不变的部分,将不变的部分抽取出来;
  • 扩展可变部分,将可变的设置抽象方法,让具体子类来实现。
  • 抽取的公共代码,便于后期维护
  • 行为有基类来控制,具体操作有子类实现。

缺点

  • 每一个不同的实现都需要有一个子类来实现,这样就会导致类的数量大大的增加,使得系统更加庞大。

模版模式的使用场景

在软件设计中,有些功能很类似,只是在某些环节不同而已。大多数环节都是相同的时候,可以使用模板模式。将通用的算法或者步骤抽取到抽象类中,在具体子类中实现具体特定的操作

模板模式的结构和实现

模式结构

模板方法模式由两部分结构组成

  • 第一部分是抽象父类

  • 第二部分是具体的实现子类。

通常在抽象父类中封装了子类的算法框架,包括实现一些公共方法以及封装子类中所有方法的执行顺序。子类通过继承这个抽象类,也继承了整个算法结构,并且可以选择重写父类的方法。

实现

此处在李老师的课程中使用下面例子讲述Template method

Templatelib.cpp
#include <iostream>

using namespace std;

//程序库开发人员
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()
    { //稳定
        cout << "Step1" << endl;
    }
    void Step3()
    { //稳定
        cout << "Step3" << endl;
    }
    void Step5()
    {   //稳定
        cout << "Step5" << endl;
    }

    virtual bool Step2() = 0; //变化
    virtual void Step4() = 0; //变化
};
Template.cpp
#include "Templatelib.cpp"
#include <iostream>

using namespace std;

//应用程序开发人员
class Application : public Library
{
  protected:
	virtual bool Step2()
	{
		//... 子类重写实现
		cout << "override Step2" << endl;
		return true;
	}

	virtual void Step4()
	{
		//... 子类重写实现
		cout << "override Step4" << endl;
	}
};

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

	delete pLib;
}

运行结果:

Step1
override Step2
Step3
override Step4
override Step4
override Step4
override Step4
Step5

分析:可以看出,通过使用模板方法,可以约束子类的行为,另子类按照父类的设定进行运行,避免子类实现的不规范,使得程序可以灵活的被调用。

实例

下面给出大话设计模式中的程序实例,通过Template pattern 实现煮茶的步骤:

CaffeineBeverage.hpp
#ifndef CAFFEINEBEVERAGE_HPP
#define CAFFEINEBEVERAGE_HPP

#include <iostream>

class CaffeineBeverage {
public:
    virtual ~CaffeineBeverage(){}

    void prepareRecipe() {
        boilWater();
        brew();
        pourInCup();
        if(customerWantsCondiments())
            addCondiments();
    }

    virtual void brew() = 0;
    virtual void addCondiments() = 0;

    void boilWater() {
        std::cout << "Boiling water\n";
    }

    void pourInCup() {
        std::cout << "Pouring into cup\n";
    }

    virtual bool customerWantsCondiments() {
        return true;
    }
};


#endif
Coffee.cpp
#ifndef COFFEE_HPP
#define COFFEE_HPP

#include "CaffeineBeverage.hpp"

#include <iostream>

class Coffee : public CaffeineBeverage {
public:
    ~Coffee(){}

    void brew() {
        std::cout << "Dripping Coffee through filter\n";
    }

    void addCondiments() {
        std::cout << "Adding Sugar and Milk\n";
    }

    bool customerWantsCondiments() {
        char c;
        std::cout << "Do you want to add condiments?\n";
        std::cin >> c;

        if(c == 'y')
            return true;
        else
            return false;
    }
};


#endif
Tea.cpp
#ifndef TEA_HPP
#define TEA_HPP

#include "CaffeineBeverage.hpp"

#include <iostream>

class Tea : public CaffeineBeverage {
public:
    ~Tea(){}

    void brew() {
        std::cout << "Steeping the tea\n";
    }

    void addCondiments() {
        std::cout << "Adding Lemon\n";
    }

    bool customerWantsCondiments()
    {
        char c;
        std::cout << "Do you want to add condiments?\n";
        std::cin >> c;

        if (c == 'y')
            return true;
        else
            return false;
    }
};

#endif
main.cpp
#include "Tea.hpp"
#include "Coffee.hpp"

int main() {
    Tea* tea = new Tea();
    Coffee* coffee = new Coffee();

    std::cout << "\nMaking tea...\n";
    tea->prepareRecipe();

    std::cout << "\nMaking coffee...\n";
    coffee->prepareRecipe();

    delete tea;
    delete coffee;
}

输出

Making tea...
Boiling water
Steeping the tea
Pouring into cup
Do you want to add condiments?
y
Adding Lemon

Making coffee...
Boiling water
Dripping Coffee through filter
Pouring into cup
Do you want to add condiments?
y
Adding Sugar and Milk

重点

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

整理自:
https://blog.csdn.net/qq_40124555/article/details/126131599
https://github.com/Bigmartin121/C-plusplus-design-patterns-Li/tree/main/Template-Pattern

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值