设计模式——模版方法和策略模式

在这里插入图片描述

前言

作为一名资深CV工程师,学会为自己减少工作量乃重中之重。但只是一味地CV,只会因为劣质代码而让自己的工作量加倍,为了将来不被繁重的维护工作而打扰自己的休息日,为了更好的节能,学习设计模式,刻不容缓。

模版方法

概念

生活中我们总是离不开各种模版的存在,作文、文章、简历的模版。正是因为这些模板的存在,我们工作的效率才大大提高,而设计模式的中模版方法正是与现实生活中的模版如出一辙。

现实中的模版一般有两类,一类为只有大体框架的,而另一类为全部都填写完的,只需要修改你想要的部分即可。我们在设计模版方法的时候,可以设计一个骨架作为调用流程,而具体的功能/算法则留给派生类来实现。或者,将那些会变化的代码逻辑封装起来,如果有需要再留给派生类更改。

定义

模版方法指的是为算法定义一个大体运行框架,而将那些会变化的代码封装起来,而留给派生类实现的一种设计模式。

代码实现

以冲泡饮料为例,冲泡的步骤基本都不会改变,只有一部分细节会有变化,正好可以使用模版方法进行设计封装。

Beverage
+void PrepareRecipe()
+~Beverage()
#void BoilWater()
#void PourInCup()
#void Brew()
#void AddCondiments()
Coffee
#void Brew()
#void AddCondiments()
Tea
#void Brew()
#void AddCondiments()

代码实例

class Beverage
{
public:
    void PrepareRecipe()
    {   // 代码运行的大体框架
        BoilWater();
        PourInCup();
        Brew();
        AddCondiments();
    }
    virtual ~Beverage() = default;
protected:
    // 具体实现可留给子类实现
    virtual void BoilWater()
    {
        std::cout << "Boiling water" << std::endl;
    }

    virtual void PourInCup()
    {
        std::cout << "Pouring into cup" << std::endl;
    }

    virtual void Brew() = 0;

    virtual void AddCondiments() = 0;
};

class Coffee : public Beverage
{
protected:
    void Brew() override { std::cout << "Brewing coffee" << std::endl; }
    void AddCondiments() override { std::cout << "Adding sugar and milk" << std::endl; }
};

class Tea : public Beverage
{
protected:
    void Brew() override { std::cout << "Brewing tea" << std::endl; }
    void AddCondiments() override { std::cout << "Adding lemon" << std::endl; }
};

钩子方法

钩子方法是模版方法的一种变体,它在框架中定义一个判断方法(钩子),让子类来决定其代码逻辑,减少了减少了外部的干预,提高了代码的灵活度与拓展性。

继续用上方的饮料代码来举例就是,不是所有都饮料中都需要添加调味剂/配料,此时可以由子类决定其算法逻辑。

代码实例

class Beverage
{
public:
    void PrepareRecipe()
    {   // 代码运行的大体框架
        BoilWater();
        PourInCup();
        Brew();
        if (NeedCondiments()) AddCondiments();
    }
    virtual ~Beverage() = default;
protected:
    // 钩子方法
    virtual bool NeedCondiments() { return false; }
    // 具体实现可留给子类实现
    virtual void BoilWater()
    {
        std::cout << "Boiling water" << std::endl;
    }

    virtual void PourInCup()
    {
        std::cout << "Pouring into cup" << std::endl;
    }

    virtual void Brew() {std::cout << "Brew some drink"; };

    virtual void AddCondiments() { std::cout << "Adding some condiments"; }
};

class Coffee : public Beverage
{
protected:
    bool NeedCondiments() override { return true; }
    void Brew() override { std::cout << "Brewing coffee" << std::endl; }
    void AddCondiments() override { std::cout << "Adding sugar and milk" << std::endl; }
};

策略模式

概念

策略模式指的是将算法封装起来(成员变量/接口),使其能够根据不同情况而更换。策略模式与模版方法都需要将其算法/实现封装起来,初认可能会将其混淆,但只要认清模版方法是将实现延迟到子类实现,而策略模式是变化封装成类(接口/委托),就不会混淆了。

这里使用支付系统作为例子,随着互联网的发展,我们的支付方式越发变得丰富,如果每增加一个支付方式,支付系统都要重写代码的话,那么想必程序员都再也不用担心失业了。这种情况下使用策略模式,将支付手段封装起来,那么就正好符合OO原则中的开闭原则,系统的维护性也更好。

Payment
+Pay(int amount)
CreditCardPayment
+Pay(int amount)
PayPalPayment
+Pay(int amount)
PaymentContext
-Payment* _payment
+PayAmount(int amount)
+SetPayment(Payment* payment)

实现

class Payment
{
public:
    virtual void Pay(int amount) = 0; // 抽象支付方式
    virtual ~Payment() = default;
};

// 不同支付方式继承与同一个接口
class CreditCardPayment : public Payment
{
public:
    void Pay(int amount) override
    {
        std::cout << "Paying " << amount << " using CreditCard" << std::endl;
    }
};

class PayPalPayment : public Payment
{
public:
    void Pay(int amount) override
    {
        std::cout << "Paying " << amount << " using PayPal" << std::endl;
    }
};

class PaymentContext
{
private:
    Payment* _payment{};
public:
    void PayAmount(int amount)
    {
        if (_payment) _payment->Pay(amount);
    }
    // 根据需要变更策略
    void SetPayment(Payment* payment) { _payment = payment;}
};

总结

特点 模板方法模式 策略模式
定义 将算法的固定部分提取到基类,变化部分由子类实现。 将不同算法封装成独立的类,通过上下文类动态切换算法。
设计意图 通过基类定义算法框架,将具体实现延迟到子类。 通过将算法封装成独立的类,使其能够在运行时动态替换。
使用场景 固定流程的多个步骤,其中部分步骤的实现因子类不同而不同。 多种算法可以互换,且算法相对独立,变化频繁。
优点 1. 代码复用性高。
2. 易于扩展新功能。
1. 符合开闭原则。
2. 代码更加灵活,易于维护和扩展。
缺点 1. 继承关系较复杂。
2. 增加类的数量。
1. 增加系统复杂度。
2. 上下文类需要了解所有策略的细节。

📜博客主页:主页
📫我的专栏:C++
📱我的github:github

相关推荐

  1. 设计模式——策略模式

    2024-07-20 07:20:06       42 阅读
  2. 设计模式-策略模式

    2024-07-20 07:20:06       55 阅读
  3. 设计模式——策略模式

    2024-07-20 07:20:06       42 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-07-20 07:20:06       52 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-07-20 07:20:06       54 阅读
  3. 在Django里面运行非项目文件

    2024-07-20 07:20:06       45 阅读
  4. Python语言-面向对象

    2024-07-20 07:20:06       55 阅读

热门阅读

  1. RK3328 Debian安装OpenMediaVault

    2024-07-20 07:20:06       16 阅读
  2. list容器

    2024-07-20 07:20:06       14 阅读
  3. http 协议中GET如何传递参数(Query String)?

    2024-07-20 07:20:06       12 阅读
  4. 浏览器的缓存

    2024-07-20 07:20:06       17 阅读
  5. 记录贴-idea导入别人的项目

    2024-07-20 07:20:06       14 阅读
  6. 【SpringBoot】分页查询

    2024-07-20 07:20:06       16 阅读
  7. 第九十六周周报

    2024-07-20 07:20:06       14 阅读
  8. Webserver笔记

    2024-07-20 07:20:06       16 阅读
  9. mybatis-sql实战总结

    2024-07-20 07:20:06       17 阅读
  10. Python--正则表达式re模块基础匹配方法

    2024-07-20 07:20:06       16 阅读
  11. 2024-07-19 Unity插件 Odin Serializer1 —— 插件介绍

    2024-07-20 07:20:06       17 阅读
  12. 【多商户自营解决方案】

    2024-07-20 07:20:06       16 阅读