自学内容网 自学内容网

实战设计模式之策略模式

概述

        与前一篇文章中提到的观察者模式一样,策略模式也是一种行为设计模式。它允许我们定义一系列算法,并将每个算法封装起来,使它们可以互换使用。通过这种方式,策略模式使得算法的变化独立于使用这些算法的客户端,从而提高了系统的灵活性和可维护性。

        商场的折扣计算是运用策略模式的一个典型例子:在促销活动中,顾客可以享受不同的折扣,包括满减优惠、会员专享折扣、节日特惠等;当顾客结账时,系统可以根据实际情况选择适用的折扣策略进行计算。这种设计使得折扣规则易于管理和扩展,同时也提高了系统的灵活性。

基本原理

        用一句话来描述策略模式的话,实际上就是将一组相关的行为抽象出来,让它们可以被替换。这意味着,我们可以根据具体情况动态地选择最适合的行为或算法,而不必修改现有代码结构。这种设计不仅遵循了面向对象编程中的开闭原则(对扩展开放,对修改关闭),还大大简化了条件逻辑。策略模式包括如下三个核心组件。

        1、策略接口。定义了一个公共接口,所有的具体策略都必须实现这个接口。这使得我们可以调用任何具体策略,而无需关心其内部实现细节。

        2、具体策略类。实现了策略接口的具体类,每个具体策略类代表了一种不同的算法或行为逻辑,这些类包含了实际执行任务的代码。

        3、上下文类。上下文类负责与具体的策略进行交互,它持有策略对象的引用,并提供一个接口供客户端调用,以执行所选策略的操作。

        基于上面的核心组件,策略模式的实现主要有以下五个步骤。

        1、定义策略接口。首先,我们需要定义一个抽象的策略接口或基类。这个接口声明了所有具体策略必须实现的方法,这些方法代表了不同的算法或行为逻辑。

        2、实现具体策略。根据实际需求,为每种不同的算法或行为逻辑创建具体策略类。每个具体策略类都应该继承自上面定义的策略接口,并且提供具体的算法实现。

        3、设计上下文类。上下文类负责与具体策略进行交互,它持有一个策略对象的引用,并通过该引用调用策略的具体实现。另外,上下文类还应该提供设置和获取当前策略的方法,以允许外部更改所使用的策略。

        4、配置策略。在应用程序启动或运行过程中,根据具体情况选择适当的策略,并将其传递给上下文。

        5、执行策略。当需要执行某个行为时,上下文会调用其持有的策略对象的方法,从而触发相应的行为或算法。

实战解析

        在下面的实战代码中,我们使用策略模式实现了购物车的折扣计算。

        首先,我们定义了一个抽象类CDiscountStrategy作为所有具体折扣策略的接口,它包含一个纯虚函数Calculate用于定义价格计算逻辑。

        接着,我们实现了三个具体策略类:CNoDiscount、CFixedAmountDiscount、CPercentageDiscount。其中,CNoDiscount表示无折扣,直接返回原价;CFixedAmountDiscount应用固定金额折扣,从原价中减去指定金额;CPercentageDiscount则根据给定的百分比来计算折后价格。

        为了管理这些策略,我们定义了购物车上下文类CShoppingCartContext。它持有一个指向当前折扣策略的指针,并提供了设置新策略和获取最终价格的方法。

        最后,在main函数中,我们创建了购物车实例,动态切换了不同的折扣策略,并打印输出各自的折后价格。

#include <iostream>
using namespace std;

// 策略接口
class CDiscountStrategy
{
public:
    virtual ~CDiscountStrategy() {}

    virtual double Calculate(double price) const = 0;
};

// 具体策略类:无折扣
class CNoDiscount : public CDiscountStrategy
{
public:
    double Calculate(double price) const override
    {
        return price;
    }
};

// 具体策略类:固定金额折扣
class CFixedAmountDiscount : public CDiscountStrategy
{
public:
    CFixedAmountDiscount(double amount) : m_discountAmount(amount) {}

    double Calculate(double price) const override
    {
        return price - m_discountAmount;
    }
private:
    double m_discountAmount;
};

// 具体策略类:百分比折扣
class CPercentageDiscount : public CDiscountStrategy
{
public:
    CPercentageDiscount(double rate) : m_discountRate(rate) {}

    double Calculate(double price) const override
    {
        return price * (1 - m_discountRate);
    }
private:
    double m_discountRate;
};

// 购物车上下文类
class CShoppingCartContext
{
public:
    CShoppingCartContext(CDiscountStrategy* pStrategy) : m_pStrategy(pStrategy) {}
    ~CShoppingCartContext()
    {
        delete m_pStrategy;
        m_pStrategy = NULL;
    }

    void SetStrategy(CDiscountStrategy* pStrategy)
    {
        if (pStrategy != m_pStrategy)
        {
            delete m_pStrategy;
            m_pStrategy = pStrategy;
        }
    }

    double GetFinalPrice(double originalPrice) const
    {
        if (m_pStrategy == NULL)
        {
            return 0.0;
        }

        return m_pStrategy->Calculate(originalPrice);
    }
private:
    CDiscountStrategy* m_pStrategy;
};

int main()
{
    // 创建购物车购物车,并设置初始折扣策略
    CShoppingCartContext cart(new CNoDiscount());
    double price = 100.0;
    cout << "Original Price: " << price << endl;
    cout << "Final Price with No Discount: " << cart.GetFinalPrice(price) << endl;

    // 更换为固定金额折扣策略
    cart.SetStrategy(new CFixedAmountDiscount(10));
    cout << "Final Price with Fixed Amount Discount: " << cart.GetFinalPrice(price) << endl;

    // 更换为百分比折扣策略
    cart.SetStrategy(new CPercentageDiscount(0.2));
    cout << "Final Price with Percentage Discount: " << cart.GetFinalPrice(price) << endl;
    return 0;
}

总结

        策略模式可有效分离变化点,它将算法的变更从使用该算法的地方分离出来,提高了代码的灵活性和可扩展性。新增加一个策略时,不需要修改现有代码,只需要添加新的具体策略类即可。另外,每个具体策略都是一个独立的类,因此可以很容易地对其进行单元测试。

        但由于每种策略都需要定义一个具体的类,可能会导致类的数量增多,增加了系统的复杂度。除此之外,为了选择合适的策略,客户端通常需要知道有哪些可用的策略以及它们的区别,这可能违反了依赖倒置原则。


原文地址:https://blog.csdn.net/hope_wisdom/article/details/144652296

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!