策略模式 Strategy Pattern

514 阅读4分钟

策略模式 Strategy Pattern

这个我觉得是恶心我挺久的也确实好用, 但是写不好的时候别人也不明白你做了啥把, 搞起

定义

定义一系列算法, 把他们封装起来, 并且使得算法可以独立于使用它的客户程序而变化

没事没事正常人都看不懂的, 反正这个策略模式最出名的就是它可以拿来消除非常臃肿的if-else

案例1

背景

某个商场节假日有固定的促销活动, 为了加大促销力度, 现在需要提升国庆节促销活动规格

分析

又到了分析的环节

稳定点: 也没啥好说的这个可以理解成促销活动是一定有的

变化点: 促销活动的力度, 促销活动的时间, 促销活动的方式

不使用策略模式之前

enum VacationEnum {
    VAC_Spring,
    VAC_Qixi,
    VAC_Wuyi,
    VAC_Guoqing
};

class Promotion {
    VacationEnum vac;
public:
    double CalcPromotion() {
        if (vac == VAC_Spring) {
            // 春节
        } else if (vac == VAC_Qixi) {
            // 七夕
        } else if (vac == VAC_Wuyi) {
            // 五一
        } else if (vac == VAC_Guoqing) {
            // 国庆
        }
        return 0;
    }
};

可以很明显的看出来如果节日或者促销方式的增加都不知道这个东西要变得有多长下去, 效率也很低

使用策略模式之后

class Context {};

class ProStrategy {
public:
    virtual double CalcPro(const Context& ctx) = 0;
    virtual ~ProStrategy();
};

class VAC_Spring : public ProStrategy {
public:
    virtual double CalcPro(const Context& ctx) {}
};

class VAC_QIYI : public ProStrategy {
public:
    virtual double CalcPro(const Context& ctx) {}
};

class VAC_QIYI1 : public VAC_QIYI {
public:
    virtual double CalcPro(const Context& ctx) {}
};

class VAC_Wuyi : public ProStrategy {
public:
    virtual double CalcPro(const Context& ctx) {}
};

class VAC_Guoqing : public ProStrategy {
public:
    virtual double CalcPro(const Context& ctx) {}
};

class Promotion {
public:
    Promotion(ProStrategy* sss) : s(sss) {}
    ~Promotion(){}
    double CalcPromotion(const Context& ctx) {
        return s->CalcPro(ctx);
    }
private:
    ProStrategy* s;
};

int main() {
    Context ctx;
    ProStrategy* s = new VAC_QIYI1;
    Promotion* p = new Promotion(s);
    p->CalcPromotion(ctx);
    return 0;
}

这么做就只需要通过类的方式, 摒弃了大量的if-else 但是感觉这个例子没有说清楚策略模式的好看第二个例子

案例2

背景

打算为游客们创建一款导游程序, 该程序的核心功能是提供美观的地图, 以帮助用户在任何城市中快速定位

用户期待的程序新功能是自动路线规划: 他们希望输入地址后就能在地图上看到前往目的地的最快路线

程序的首个版本只能规划公路路线; 驾车旅行的人们对此非常满意

但很显然, 并非所有人都会在度假时开车; 因此你在下次更新时添加了规划步行路线的功能; 此后, 你又添加了规划公共交通路线的功能

而这只是个开始, 不久后, 你又要为骑行者规划路线; 又过了一段时间, 你又要为游览城市中的所有景点规划路线

终于在某个时候, 你觉得自己没法继续维护这堆代码了

解决方案

策略模式建议找出负责用许多不同方式完成特定任务的类, 然后将其中的算法抽取到一组被称为策略的独立类中

名为上下文的原始类必须包含一个成员变量来存储对于每种策略的引用

上下文并不执行任务, 而是将工作委派给已连接的策略对象

上下文不负责选择符合任务需要的算法, 客户端会将所需策略传递给上下文; 实际上, 上下文并不十分了解策略, 它会通过同样的通用接口与所有策略进行交互, 而该接口只需暴露一个方法来触发所选策略中封装的算法即可

因此, 上下文可独立于具体策略; 这样你就可在不修改上下文代码或其他策略的情况下添加新算法或修改已有算法了

image.png

在导游应用中, 每个路线规划算法都可被抽取到只有一个 buildRoute生成路线方法的独立类中; 该方法接收起点和终点作为参数, 并返回路线中途点的集合

即使传递给每个路径规划类的参数一模一样, 其所创建的路线也可能完全不同

主要导游类的主要工作是在地图上渲染一系列中途点, 不会在意如何选择算法

该类中还有一个用于切换当前路径规划策略的方法, 因此客户端可用其他策略替换当前选择的路径规划行为

要点

  • 策略模式提供了一系列可重用的算法, 从而使的类型在运行时方便根据需求在各个算法之间进行切换
  • 策略模式消除了大量的if-else, 其实就是解耦合高可用

总结

感觉策略模式挺难用的非常好还是要写过很多做过更多的业务才能对它理解的更好

资料