汇总目录请点击访问:《设计模式目录汇总》
喜欢内容的话欢迎关注、点赞、收藏!感谢支持,祝大家祉猷并茂,顺遂无虞!
策略模式(Strategy Pattern)详解
定义
策略模式是一种行为型设计模式,它允许你在运行时选择算法或行为,而不是在编译时确定。通过将具体算法封装成独立的类,并通过一个统一的接口与客户端交互,可以实现算法的动态替换,同时避免了代码的重复和复杂条件语句。
通俗地说,策略模式就像换工具干活:你有一堆工具(算法),可以根据任务需要随时选择最合适的那个,而不用修改已有工具或任务逻辑。
生活中的例子
支付方式
当你购物结算时,可以选择支付宝、微信支付、信用卡等不同方式。这些支付方式是不同的“策略”,系统根据用户选择动态调用对应策略。
导航应用
地图导航中可以选择不同的路径规划方式,如“最短时间”、“最短距离”或“避开拥堵”。每种规划方式对应一个策略。
促销活动
商场在不同节日可能有“满减”、“折扣”或“积分兑换”等促销方案,策略模式可以轻松切换不同的促销方案。
策略模式的特点
优点
简化代码:避免复杂的条件语句(如if-else
或 switch
)。易于扩展:新增算法时,只需增加一个策略类,不影响其他代码。行为动态化:可以在运行时更换策略,提升程序灵活性。 缺点
类数增加:每个策略都需要一个类,可能导致类数量激增。客户端需要了解不同策略:客户端需要知道何时选择哪个策略。适用场景
场景
示例
行为变化需要动态选择
支付方式切换、算法选择
减少条件语句的复杂性
替代复杂的 if-else
或 switch
语句
需要扩展算法或行为
新增促销活动、增加新的导航规划方式
策略模式的实现步骤
定义策略接口
所有策略(算法)共有的接口,规定统一的方法签名。
实现具体策略
每个策略(算法)实现该接口,封装具体的行为。
定义上下文类(Context)
上下文持有策略的引用,负责调用策略对象的算法,而无需关心策略的具体实现。
客户端动态设置策略
客户端通过上下文动态选择需要使用的策略。
策略模式与其他模式的对比
特性 | 策略模式 | 工厂方法模式 |
---|---|---|
核心关注点 | 动态切换算法或行为,将算法封装成对象,使得算法可以相互替换。 | 动态创建对象,将对象的创建和使用分离,使得系统更容易扩展。 |
行为扩展方式 | 添加新的策略实现类,不需要修改原有代码,只需添加新的策略类即可扩展新的行为。 | 添加新的工厂或子类,不需要修改原有工厂代码,只需添加新的工厂类即可创建新的对象。 |
客户端角色 | 客户端需要了解并选择策略,以便在运行时根据需要选择和切换不同的策略。 | 客户端通常只需调用工厂方法来获取所需的对象,不关心对象是如何被创建和表示的。 |
C++ 示例:支付方式选择
#include <iostream>#include <memory>#include <string>using namespace std;// 策略接口class PaymentStrategy {public: virtual void pay(int amount) = 0; virtual ~PaymentStrategy() = default;};// 具体策略:支付宝支付class Alipay : public PaymentStrategy {public: void pay(int amount) override { cout << "Paid " << amount << " using Alipay." << endl; }};// 具体策略:信用卡支付class CreditCard : public PaymentStrategy {public: void pay(int amount) override { cout << "Paid " << amount << " using Credit Card." << endl; }};// 上下文类class PaymentContext {private: unique_ptr<PaymentStrategy> strategy;public: void setStrategy(unique_ptr<PaymentStrategy> newStrategy) { strategy = move(newStrategy); } void executePayment(int amount) { if (strategy) { strategy->pay(amount); } else { cout << "No payment strategy set!" << endl; } }};// 客户端代码int main() { PaymentContext context; // 使用支付宝支付 context.setStrategy(make_unique<Alipay>()); context.executePayment(100); // 切换到信用卡支付 context.setStrategy(make_unique<CreditCard>()); context.executePayment(200); return 0;}
C# 示例:导航规划
using System;// 策略接口public interface IRouteStrategy { void BuildRoute(string start, string end);}// 具体策略:最短时间路径public class FastestRoute : IRouteStrategy { public void BuildRoute(string start, string end) { Console.WriteLine($"Building the fastest route from {start} to {end}."); }}// 具体策略:最短距离路径public class ShortestRoute : IRouteStrategy { public void BuildRoute(string start, string end) { Console.WriteLine($"Building the shortest route from {start} to {end}."); }}// 上下文类public class Navigator { private IRouteStrategy _strategy; public void SetStrategy(IRouteStrategy strategy) { _strategy = strategy; } public void BuildRoute(string start, string end) { if (_strategy != null) { _strategy.BuildRoute(start, end); } else { Console.WriteLine("No route strategy set!"); } }}// 客户端代码class Program { static void Main(string[] args) { var navigator = new Navigator(); // 使用最短时间路径 navigator.SetStrategy(new FastestRoute()); navigator.BuildRoute("Home", "Office"); // 切换到最短距离路径 navigator.SetStrategy(new ShortestRoute()); navigator.BuildRoute("Home", "Gym"); }}
策略模式的类图
策略模式总结
灵活性高:可以轻松地添加新策略,扩展性好。职责清晰:将算法逻辑封装在独立的策略类中,简化了上下文的代码。场景适配:非常适合需要动态切换行为或算法的场景,比如支付系统、导航系统等。注意点:避免类爆炸(策略类过多),并且客户端需要了解可用策略的功能。欢迎关注、点赞、收藏!更多系列内容可以点击专栏目录订阅,感谢支持,再次祝大家祉猷并茂,顺遂无虞!
若将文章用作它处,请一定注明出处,商用请私信联系我!