2023-7-8-第十四式策略模式

简介: 2023-7-8-第十四式策略模式

😉一、基础概念

策略模式(Strategy Pattern)是一种行为型设计模式,它允许在运行时选择算法的行为。策略模式将不同的算法或行为封装在独立的类中,并使得它们可以互相替换,而客户端代码则不需要了解具体的实现细节。

在策略模式中,通常包含以下几个角色:

  1. 环境(Context):环境类持有一个策略对象的引用,并在运行时调用策略对象的方法。环境类提供了一个接口,允许客户端在运行时动态地切换不同的策略。
  2. 抽象策略(Strategy):抽象策略定义了一个共同的接口,声明了一个或多个策略方法,每个方法对应了一个具体的算法或行为。所有具体策略类都要实现这个接口。
  3. 具体策略(Concrete Strategy):具体策略类实现了抽象策略中定义的方法,每个具体策略类提供了自己的算法或行为实现。

通过使用策略模式,可以实现算法的解耦和灵活性。客户端可以根据需求动态地选择和切换不同的策略,而无需修改大量的代码。

策略模式适用于以下情况:

  • 当有多个相关的类仅在算法或行为上有所不同时,可以使用策略模式来避免大量的条件语句。
  • 当需要在运行时动态地选择不同的算法或行为时,策略模式可以提供灵活性。
  • 当需要对算法进行扩展或修改时,可以通过添加新的具体策略类来实现,而无需修改已有代码。

总而言之,策略模式通过将算法封装在独立的类中,使得它们可以互相替换并与客户端解耦。这种设计模式提供了一种灵活的方式来处理多个相关类的算法差异,并支持运行时动态选择算法的能力。


🐱‍🐉二、策略模式实现

在C++中,可以使用策略模式通过接口和多态来实现。下面是一个简单的示例:

#include <iostream>
// 抽象策略类
class Strategy {
public:
    virtual void execute() = 0;
};
// 具体策略类A
class ConcreteStrategyA : public Strategy {
public:
    void execute() override {
        std::cout << "Executing strategy A" << std::endl;
        // 实现具体的算法或行为
    }
};
// 具体策略类B
class ConcreteStrategyB : public Strategy {
public:
    void execute() override {
        std::cout << "Executing strategy B" << std::endl;
        // 实现具体的算法或行为
    }
};
// 环境类
class Context {
private:
    Strategy* strategy;
public:
    Context(Strategy* strat) : strategy(strat) {}
    void setStrategy(Strategy* strat) {
        strategy = strat;
    }
    void executeStrategy() {
        strategy->execute();
    }
};
int main() {
    // 创建具体策略对象
    ConcreteStrategyA strategyA;
    ConcreteStrategyB strategyB;
    // 创建环境对象,并设置初始策略为策略A
    Context context(&strategyA);
    // 执行策略A
    context.executeStrategy();
    // 设置策略为策略B,并执行
    context.setStrategy(&strategyB);
    context.executeStrategy();
    return 0;
}

在上述示例中,我们定义了抽象策略类 Strategy,并派生出两个具体策略类 ConcreteStrategyAConcreteStrategyB。这些具体策略类实现了抽象策略类中的纯虚函数,即各自的执行方法。

然后,我们定义了环境类 Context,它持有一个指向抽象策略类的指针,并提供了设置策略和执行策略的方法。

main() 函数中,我们创建具体策略对象,并通过将其传递给环境对象来设置初始策略。然后,我们调用环境对象的执行策略方法来执行当前设置的策略。

通过使用接口和多态,策略模式实现了算法的解耦和灵活性。我们可以根据需要动态地选择和切换不同的策略。


🎉三、模块之间的关系

策略模式涉及以下几个模块之间的关系:

  1. 环境类(Context):环境类是策略模式的核心,它持有一个策略对象的引用,并在运行时调用该策略对象的方法。环境类实现了客户端与具体策略类之间的解耦,客户端只需要与环境类进行交互即可。
  2. 抽象策略类(Strategy):抽象策略类定义了策略所需的接口或协议,它声明了一个或多个策略方法。这些方法代表不同的算法或行为,具体策略类必须实现这些方法。
  3. 具体策略类(Concrete Strategy):具体策略类是抽象策略类的派生类,它实现了抽象策略类中定义的策略方法。每个具体策略类提供了自己的算法或行为实现。在策略模式中,可以有多个具体策略类,代表不同的策略选项。

通过上述模块之间的关系,策略模式实现了一种动态选择算法的机制。客户端只需与环境类交互,并通过设置不同的策略对象来改变算法的行为。客户端不需要了解具体的策略实现细节,只需调用环境类提供的统一接口即可。

此外,策略模式还可以通过工厂类或依赖注入等方式来创建和管理具体策略对象。这样可以进一步降低客户端与具体策略类之间的耦合,并提供更大的灵活性和可扩展性。


🐱‍🚀四、注意事项

当使用策略模式时,有一些注意事项需要考虑:

  1. 接口设计:确保抽象策略类定义了清晰和一致的接口,以确保所有具体策略类都能正确实现这些方法。良好的接口设计有助于减少后续修改的风险。
  2. 策略数量:在设计时要合理考虑策略的数量。如果策略过多,可能会导致代码复杂性增加,并且选择合适的策略变得困难。可根据实际需求,避免过度设计。
  3. 策略切换开销:在运行时切换策略时,可能会引入一定的开销。因此,在选择是否使用策略模式时,应权衡灵活性和性能之间的权衡。
  4. 客户端责任:客户端负责选择合适的策略并将其传递给环境类。客户端需要理解不同策略之间的区别和适用场景,以确保选择最合适的策略。
  5. 策略共享状态:如果多个策略对象之间需要共享状态,需要谨慎处理。确保共享状态的一致性和线程安全性,或者考虑将状态存储在环境类中而不是策略对象中。
  6. 代码重用和维护:策略模式可以促进代码重用和维护。确保策略之间的差异明确,并遵循单一职责原则,以便更容易扩展和修改具体策略。
  7. 需求变化:当需求发生变化时,可能需要添加新的策略或修改现有的策略。在设计时要考虑到这种变化,并尽量使系统具有弹性,以方便适应未来的需求变更。

总之,使用策略模式需要仔细考虑接口设计、策略数量、切换开销和共享状态等因素。理解策略模式的优缺点并根据实际情况进行合理的设计和使用,可帮助提高代码的灵活性、可维护性和可扩展性。


🎂五、使用场景

策略模式适用于以下场景:

  1. 算法或行为的差异化:当有多个相关的类仅在算法或行为上有所不同时,可以使用策略模式来避免大量的条件语句。例如,不同的支付方式(信用卡、支付宝、微信支付)具有不同的支付算法。
  2. 运行时动态选择算法:当需要在运行时动态地选择不同的算法或行为时,策略模式可以提供灵活性。例如,根据用户的偏好设置,在游戏中选择不同的难度级别。
  3. 算法的扩展和修改:如果希望能够方便地对算法进行扩展或修改,可以通过添加新的具体策略类来实现,而无需修改已有代码。这样可以降低代码的耦合性,并且符合开闭原则。
  4. 客户端与算法的解耦:策略模式将具体的算法封装在独立的策略类中,使得客户端与具体算法的实现细节解耦。客户端只需使用抽象策略类和环境类进行交互,而无需了解具体算法的实现细节。
  5. 多态替代条件语句:使用策略模式可以避免使用大量的条件语句,提高代码的可读性和可维护性。通过多态特性,可以将不同的算法封装在具体策略类中,以更简洁、清晰的方式实现业务逻辑。

总而言之,策略模式适用于需要根据不同情况选择不同算法或行为的场景,并且可以灵活地扩展和修改算法。它帮助降低代码的耦合性,提高代码的可读性和可维护性。


🍳参考文献

🧊文章总结

提示:这里对文章进行总结:

   本文讲了关于策略模式的知识。



目录
打赏
0
0
0
0
5
分享
相关文章
zabbix监控交换机出图断断续续问题解决
Zabbix通过snmp监控Nexus7K流量时,之前经常出现出图很不稳定的情况。我先对zabbix以及snmp是怎么来监控流量的做个简单的说明: Zabbix:只是负责从自身配置中的snmp部分拿到数据绘图、告警等等。
3068 0
一文看懂分布式链路监控系统
本文通过阿里的Eagleeye(鹰眼)和开源的Skywalking,从数据模型、数据埋点以及数据存储三个方面介绍分布式链路监控系统的实现细节,其中将重点介绍Skywalking字节码增强的实现方案。
739 1
浅谈使用PageHelper-Mybatis通用分页插件
浅谈使用PageHelper-Mybatis通用分页插件
QGS
269 0
quartz的cron表达式
按顺序依次为 秒(0~59) 分钟(0~59) 小时(0~23) 天(月)(0~31,但是你需要考虑你月的天数)月(0~11) 天(星期)(1~7 1=SUN 或 SUN,MON,TUE,WED,THU,FRI,SAT) 7.年份(1970-2099) 其中每个元素可以是一个值(如6),一个连续区间(9-12),一个间隔时间(8-18/4)(/表示每隔4小时),一个列表(1,3,5),通配符。
2182 0
springboot+vue毕业设计选题系统
本毕业设计选题系统是针对目前毕业设计选题管理的实际需求,从实际工作出发,对过去的毕业设计选题管理系统存在的问题进行分析,完善用户的使用体会。采用计算机系统来管理信息,取代人工管理模式,查询便利,信息准确率高,节省了开支,提高了工作的效率。本系统结合计算机系统的结构、概念、模型、原理、方法,在计算机各种优势的情况下,采用JAVA语言,结合SpringBoot框架与Vue框架以及MYSQL数据库设计并实现的。本毕业设计选题管理系统主要包括个人中心、用户管理、选题信息管理、设计信息管理等多个模块。它帮助毕业设计选题管理实现了信息化、网络化,通过测试,实现了系统设计目标,相比传统的管理模式,本系统合理
461 0
知识体系化的必要性及构建通用体系的方法
知识体系化的必要性及构建通用体系的方法
424 0
如何从 0 到 1 参与 Flink 社区?
本文首先介绍为何要参与开源社区以及在参与开源社区的过程中需要注意什么,然后重点介绍如何参与 Flink 社区以及在社区里面提交 PR 的整个流程。
如何从 0 到 1 参与 Flink 社区?
|
11月前
补码浮点数运算(设数的阶码为3位,尾数为6位(均不包括符号位)按机械补码浮点运算规则完成下列[x+y]补运算。)
补码浮点数运算(设数的阶码为3位,尾数为6位(均不包括符号位)按机械补码浮点运算规则完成下列[x+y]补运算。)
476 0
反序列化漏洞原理/防御
列化就是将对象转换成字节流,可以更方便的将数据保存到本地文件 反序列化就是将字节流还原成对象
992 0
|
11月前
|
解决报错:import sun.misc.BASE64Decoder无法找到
解决报错:import sun.misc.BASE64Decoder无法找到
176 0