策略模式实战:从代码冗余到优雅扩展,C++程序员必学的设计模式秘籍

📕目录

前言

一、为什么需要策略模式?先看一个“反例”

二、策略模式核心原理:3个角色搞定解耦

1. 抽象策略(Strategy)

2. 具体策略(Concrete Strategy)

3. 上下文(Context)

策略模式UML类图

三、实战:用策略模式重构电商折扣系统

1. 第一步:定义策略参数类(可选但推荐)

2. 第二步:定义抽象策略接口

3. 第三步:实现具体策略类

4. 第四步:实现上下文类

5. 第五步:客户端测试代码

6. 运行结果与分析

四、策略模式进阶:优化与扩展技巧

1. 用智能指针替代裸指针,避免内存泄漏

2. 结合工厂模式,解决策略选择问题

3. 策略模式与模板方法模式的区别

五、策略模式的优缺点与适用场景

1. 优点

2. 缺点

3. 适用场景

六、实际开发中的策略模式应用案例

1. 支付系统

2. 日志系统

3. 排序算法

4. 表单验证

七、总结:策略模式的核心价值


class 卑微码农:
    def __init__(self):
        self.技能 = ['能读懂十年前祖传代码', '擅长用Ctrl+C/V搭建世界', '信奉"能跑就别动"的玄学']
        self.发量 = 100  # 初始发量
        self.咖啡因耐受度 = '极限'
        
    def 修Bug(self, bug):
        try:
            # 试图用玄学解决问题
            if bug.严重程度 == '离谱':
                print("这一定是环境问题!")
            else:
                print("让我看看是谁又没写注释...哦,是我自己。")
        except Exception as e:
            # 如果try块都救不了,那就...
            print("重启一下试试?")
            self.发量 -= 1  # 每解决一个bug,头发-1
 
 
# 实例化一个我
我 = 卑微码农()

前言

我们总会遇到这样的场景:一段代码里堆满了if-elseswitch分支,每个分支对应一种业务逻辑。比如电商平台的折扣计算,普通用户、VIP用户、会员用户各有不同规则,逢年过节还要叠加节日活动折扣;再比如支付系统,支付宝、微信支付、银行卡支付的调用流程完全不同。

刚开始写的时候还挺清晰,可随着业务迭代,新的折扣规则、新的支付方式不断加进来,代码就变得越来越臃肿。某天突然发现,改一个小逻辑要翻十几行分支,改完还得小心翼翼地测所有分支——这就是典型的“分支地狱”。

而策略模式,就是专门解决这种“分支冗余”问题的设计模式利器。它能让不同的业务逻辑像“插件”一样灵活切换,既保证代码整洁,又让扩展变得轻松。今天咱们就从实际开发场景出发,用C++手把手带你吃透策略模式,从原理到实战,再到进阶技巧,一篇文章全搞定。

一、为什么需要策略模式?先看一个“反例”

在讲概念之前,咱们先身临其境写一段“坏代码”,感受一下没有策略模式的痛苦。假设我们要开发一个电商平台的订单价格计算模块,核心需求是根据用户类型计算折扣后金额。

最初的需求很简单,只有普通用户和VIP用户两种:普通用户无折扣,VIP用户9折。咱们很自然地会写出这样的代码:

#include <iostream>
#include <string>
using namespace std;

// 订单类
class Order {
private:
    string userType;  // 用户类型:"normal"普通用户,"vip"VIP用户
    double amount;    // 订单原始金额
public:
    Order(string type, double amt) : userType(type), amount(amt) {}
    
    // 计算最终金额
    double calculateFinalAmount() {
        double finalAmt = 0.0;
        // 根据用户类型判断折扣
        if (userType == "normal") {
            finalAmt = amount;  // 普通用户无折扣
            cout << "普通用户,无折扣" << endl;
        } else if (userType == "vip") {
            finalAmt = amount * 0.9;  // VIP用户9折
            cout << "VIP用户,9折优惠" << endl;
        }
        return finalAmt;
    }
};

// 测试代码
int main() {
    Order order1("normal", 100.0);
    cout << "订单1最终金额:" << order1.calculateFinalAmount() << endl;
    
    Order order2("vip", 200.0);
    cout << "订单2最终金额:" << order2.calculateFinalAmount() << endl;
    
    return 0;
}

这段代码运行起来完全没问题,输出结果也符合预期。但好景不长,业务来了新需求:

  • 新增“超级会员”用户,享受8折优惠,且生日当月额外9.5折叠加;

  • 新增“节日活动”,所有用户在活动期间可享受满100减20的优惠,与用户折扣二选一(取最优);

  • 新增“新人券”,新用户首次下单可使用50元无门槛券,与其他优惠可叠加。

这下咱们得修改calculateFinalAmount方法了,修改后的代码可能变成这样(只保留核心逻辑):

// 新增参数:是否为生日月、是否有节日活动、是否为新用户
double calculateFinalAmount(bool isBirthMonth, bool isFestival, bool isNewUser) {
    double finalAmt = amount;
    // 1. 用户类型折扣
    if (userType == "normal") {
        cout << "普通用户,无折扣" << endl;
    } else if (userType == "vip") {
        finalAmt = amount * 0.9;
        cout << "VIP用户,9折优惠" << endl;
    } else if (userType == "super_vip") {
        finalAmt = amount * 0.8;
        if (isBirthMonth) {
            finalAmt *= 0.95;
            cout << "超级会员生日月,8折叠加9.5折" << endl;
        } else {
            cout << "超级会员,8折优惠" << endl;
        }
    }
    
    // 2. 节日活动优惠(与用户折扣二选一)
    if (isFestival) {
        double festivalAmt = (amount >= 100) ? (amount - 20 * (amount / 100)) : amount;
        if (festivalAmt < finalAmt) {
            finalAmt = festivalAmt;
            cout << "节日活动优惠更优,切换为满100减20" << endl;
        }
    }
    
    // 3. 新人券优惠(可叠加)
    if (isNewUser && userType == "normal") {
        finalAmt = max(0.0, finalAmt - 50);
        cout << "新人券抵扣50元" << endl;
    }
    
    return finalAmt;
}

看到这里,相信你已经感受到了“绝望”:代码里的分支越来越多,逻辑嵌套越来越深,参数也从无到有增加了3个。如果后续再新增“企业用户折扣”“积分抵扣”等需求,这个方法会彻底变成“一锅乱粥”。

这种代码的问题很明显:

  1. 违反“开闭原则”:新增优惠规则必须修改原有方法,改代码时很容易误触其他分支,风险极高;

  2. 代码可读性差:几十行甚至上百行的分支嵌套,新接手的同事可能要花半天才能理清逻辑;

  3. 复用性差:如果其他模块(比如优惠券模块)需要用到用户折扣规则,只能复制粘贴代码,造成冗余;

  4. 测试成本高:每个新规则都要重新测试所有分支组合,测试用例呈指数级增长。

而策略模式,就是解决这些问题的“特效药”。它的核心思想很简单:把变化的逻辑(比如各种折扣规则)抽离出来,封装成独立的“策略”,让策略之间可以灵活切换,而主体代码(订单类)不需要修改

二、策略模式核心原理:3个角色搞定解耦

策略模式(Strategy Pattern)是一种行为型设计模式,它定义了一系列算法(策略),并将每个算法封装起来,使它们可以相互替换。策略模式让算法的变化独立于使用算法的客户。

要理解策略模式,只需记住它的3个核心角色,这3个角色共同构成了策略模式的骨架:

1. 抽象策略(Strategy)

定义所有具体策略的公共接口,通常是一个抽象类或纯虚函数接口。它规定了策略必须实现的核心方法(比如“计算折扣”)。

作用:统一策略的调用方式,让客户端可以通过同一个接口调用不同的策略,无需关心策略的具体实现。

2. 具体策略(Concrete Strategy)

实现抽象策略定义的接口,封装具体的算法逻辑(比如普通用户策略、VIP用户策略)。每个具体策略都是一个独立的类,专注于自己的业务逻辑。

作用:承载具体的业务算法,是策略模式中“变化”的部分。新增策略只需新增一个具体策略类,无需修改其他代码。

3. 上下文(Context)

持有一个抽象策略的引用(或指针),负责与客户端交互,将具体的算法调用委托给策略对象。上下文本身不实现具体的算法,而是通过策略对象来完成业务逻辑。

作用:隔离客户端与策略类,让客户端无需直接操作策略对象,只需通过上下文切换策略即可。

策略模式UML类图

结合咱们的电商折扣场景,策略模式的UML类图如下(用简单易懂的方式描述):

从类图可以看出,策略模式的核心是“面向抽象编程”:上下文(OrderContext)依赖于抽象策略(DiscountStrategy),而不是具体策略。这样一来,具体策略的变化不会影响上下文,完美符合“开闭原则”。

三、实战:用策略模式重构电商折扣系统

理解了核心原理后,咱们就用策略模式重构前面的电商折扣系统。重构的思路是:先定义抽象策略接口,再实现所有具体策略类,最后用上下文类封装策略的调用逻辑。

1. 第一步:定义策略参数类(可选但推荐)

不同的策略可能需要不同的参数(比如超级会员需要“是否生日月”,节日策略不需要)。如果直接把参数写在策略方法里,会导致参数列表越来越长。咱们可以定义一个统一的策略参数类,用结构体或类封装所有可能用到的参数,这样后续新增参数只需修改这个类,无需改动所有策略。

#include <iostream>
#include <string>
#include <algorithm>  // 用于max函数
using namespace std;

// 策略参数类:封装所有策略可能用到的参数
struct StrategyParams {
    bool isBirthMonth = false;    // 是否为超级会员生日月
    bool isFestival = false;      // 是否有节日活动
    bool isNewUser = false;       // 是否为新用户
    string userType;              // 用户类型(冗余,实际可从上下文获取)
};

2. 第二步:定义抽象策略接口

抽象策略接口只定义核心方法calculateDiscount,接收订单金额和策略参数,返回折扣后的金额(或折扣比例,这里直接返回金额更直观)。

// 抽象折扣策略接口
class DiscountStrategy {
public:
    // 纯虚函数:计算折扣后金额
    virtual double calculateDiscount(double amount, const StrategyParams& params) = 0;
    // 虚析构函数:确保子类对象正确析构
    virtual ~DiscountStrategy() {}
    // 可选:获取策略名称,用于日志输出
    virtual string getStrategyName() const = 0;
};

这里要注意两点:一是必须定义虚析构函数,否则当用父类指针指向子类对象并删除时,会导致子类析构函数不被调用,造成内存泄漏;二是新增getStrategyName方法,方便后续输出日志,提升代码可读性。

3. 第三步:实现具体策略类

每个具体策略类都继承自抽象策略接口,实现calculateDiscount方法,专注于自己的折扣逻辑。咱们按需求实现以下策略:

  • 普通用户策略(无折扣,支持新人券);

  • VIP用户策略(9折);

  • 超级会员策略(8折,生日月叠加9.5折);

  • 节日活动策略(满100减20)。

// 1. 普通用户策略
class NormalUserStrategy : public DiscountStrategy {
public:
    double calculateDiscount(double amount, const StrategyParams& params) override {
        double discountedAmt = amount;
        // 新用户可叠加50元新人券
        if (params.isNewUser) {
            discountedAmt = max(0.0, discountedAmt - 50);
        }
        return discountedAmt;
    }
    
    string getStrategyName() const override {
        return params.isNewUser ? "普通用户(含新人券)" : "普通用户";
    }
private:
    // 可存储策略相关的配置,比如新人券金额(这里写死50,实际可从配置文件读取)
    const double newUserCoupon = 50.0;
};

// 2. VIP用户策略
class VipUserStrategy : public DiscountStrategy {
public:
    double calculateDiscount(double amount, const StrategyParams& params) override {
        // VIP固定9折,不叠加新人券(业务规则)
        return amount * 0.9;
    }
    
    string getStrategyName() const override {
        return "VIP用户";
    }
private:
    const double discountRate = 0.9;  // 折扣率,可配置
};

// 3. 超级会员策略
class SuperVipUserStrategy : public DiscountStrategy {
public:
    double calculateDiscount(double amount, const StrategyParams& params) override {
        double rate = 0.8;  // 基础8折
        if (params.isBirthMonth) {
            rate *= 0.95;   // 生日月叠加9.5折
        }
        return amount * rate;
    }
    
    string getStrategyName() const override {
        return params.isBirthMonth ? "超级会员(生日月)" : "超级会员";
    }
private:
    const double baseRate = 0.8;     // 基础折扣率
    const double birthMonthRate = 0.95;  // 生日月叠加率
};

// 4. 节日活动策略
class FestivalStrategy : public DiscountStrategy {
public:
    double calculateDiscount(double amount, const StrategyParams& params) override {
        // 满100减20,不设上限
        int reduceCount = static_cast<int>(amount / 100);
        return amount - reduceCount * 20;
    }
    
    string getStrategyName() const override {
        return "节日活动(满100减20)";
    }
private:
    const double fullAmount = 100.0;  // 满减门槛
    const double reduceAmount = 20.0; // 减扣金额
};

每个具体策略类都非常“纯粹”,只负责自己的折扣逻辑,代码简洁易懂。如果后续新增“企业用户策略”,只需新建一个类继承DiscountStrategy,实现对应的方法即可,完全不用修改原有代码——这就是“开闭原则”的魅力。

4. 第四步:实现上下文类

上下文类(OrderContext)是客户端与策略类之间的“桥梁”,它持有抽象策略的指针,提供设置策略的方法,并封装最终的金额计算逻辑(比如策略的选择、优惠的叠加规则)。

// 上下文类:订单上下文
class OrderContext {
public:
    // 构造函数:默认使用普通用户策略
    OrderContext() : strategy(new NormalUserStrategy()) {}
    
    // 析构函数:释放策略对象
    ~OrderContext() {
        if (strategy != nullptr) {
            delete strategy;
            strategy = nullptr;
        }
    }
    
    // 禁止拷贝构造和赋值运算符(避免浅拷贝导致重复析构)
    OrderContext(const OrderContext&) = delete;
    OrderContext& operator=(const OrderContext&) = delete;
    
    // 设置策略:切换不同的折扣策略
    void setStrategy(DiscountStrategy* newStrategy) {
        if (newStrategy == nullptr) {
            cout << "策略不能为空!" << endl;
            return;
        }
        // 释放旧策略
        delete strategy;
        // 指向新策略
        strategy = newStrategy;
    }
    
    // 计算最终金额:封装策略调用和业务规则(比如策略二选一等)
    double calculateFinalAmount(double amount, const StrategyParams& params) {
        if (amount <= 0) {
            cout << "订单金额无效!" << endl;
            return 0.0;
        }
        
        // 1. 计算用户类型对应的折扣金额
        double userDiscounted = strategy->calculateDiscount(amount, params);
        cout << "【" << strategy->getStrategyName() << "】折扣后金额:" << userDiscounted << endl;
        
        // 2. 如果有节日活动,计算节日折扣金额,取两者最小值(二选一)
        double finalAmt = userDiscounted;
        if (params.isFestival) {
            FestivalStrategy festivalStrategy;
            double festivalDiscounted = festivalStrategy.calculateDiscount(amount, params);
            cout << "【" << festivalStrategy.getStrategyName() << "】折扣后金额:" << festivalDiscounted << endl;
            
            if (festivalDiscounted < finalAmt) {
                finalAmt = festivalDiscounted;
                cout << "选择更优的节日活动优惠" << endl;
            } else {
                cout << "选择更优的用户类型优惠" << endl;
            }
        }
        
        return finalAmt;
    }
private:
    DiscountStrategy* strategy;  // 持有抽象策略的指针
};

上下文类的设计有几个关键点:

  1. 策略管理:通过setStrategy方法实现策略的动态切换,客户端无需直接创建策略对象;

  2. 资源释放:在析构函数中释放策略对象,避免内存泄漏;同时禁止拷贝构造和赋值运算符,防止浅拷贝导致的重复析构问题;

  3. 业务规则封装:将“用户折扣与节日折扣二选一”的业务规则封装在calculateFinalAmount方法中,客户端无需关心规则细节;

  4. 默认策略:构造函数中设置默认策略(普通用户),提升代码健壮性。

5. 第五步:客户端测试代码

客户端只需创建上下文对象,根据业务场景设置对应的策略,然后调用计算方法即可。代码非常简洁,完全看不到复杂的分支逻辑。

// 测试不同场景下的折扣计算
int main() {
    // 场景1:普通新用户,无节日活动
    cout << "===== 场景1:普通新用户,无节日活动 =====" << endl;
    OrderContext order1;  // 默认普通用户策略
    StrategyParams params1 = {false, false, true, "normal"};
    double final1 = order1.calculateFinalAmount(120.0, params1);
    cout << "场景1最终金额:" << final1 << endl << endl;
    
    // 场景2:VIP用户,节日活动期间
    cout << "===== 场景2:VIP用户,节日活动期间 =====" << endl;
    OrderContext order2;
    order2.setStrategy(new VipUserStrategy());  // 切换为VIP策略
    StrategyParams params2 = {false, true, false, "vip"};
    double final2 = order2.calculateFinalAmount(250.0, params2);
    cout << "场景2最终金额:" << final2 << endl << endl;
    
    // 场景3:超级会员生日月,无节日活动
    cout << "===== 场景3:超级会员生日月,无节日活动 =====" << endl;
    OrderContext order3;
    order3.setStrategy(new SuperVipUserStrategy());  // 切换为超级会员策略
    StrategyParams params3 = {true, false, false, "super_vip"};
    double final3 = order3.calculateFinalAmount(300.0, params3);
    cout << "场景3最终金额:" << final3 << endl << endl;
    
    // 场景4:超级会员非生日月,节日活动期间
    cout << "===== 场景4:超级会员非生日月,节日活动期间 =====" << endl;
    OrderContext order4;
    order4.setStrategy(new SuperVipUserStrategy());
    StrategyParams params4 = {false, true, false, "super_vip"};
    double final4 = order4.calculateFinalAmount(300.0, params4);
    cout << "场景4最终金额:" << final4 << endl << endl;
    
    return 0;
}

6. 运行结果与分析

编译运行上述代码,输出结果如下:

===== 场景1:普通新用户,无节日活动 =====
【普通用户(含新人券)】折扣后金额:70
场景1最终金额:70

===== 场景2:VIP用户,节日活动期间 =====
【VIP用户】折扣后金额:225
【节日活动(满100减20)】折扣后金额:210
选择更优的节日活动优惠
场景2最终金额:210

===== 场景3:超级会员生日月,无节日活动 =====
【超级会员(生日月)】折扣后金额:228
场景3最终金额:228

===== 场景4:超级会员非生日月,节日活动期间 =====
【超级会员】折扣后金额:240
【节日活动(满100减20)】折扣后金额:240
选择更优的用户类型优惠
场景4最终金额:240

从结果可以看出,所有场景的计算都符合业务规则,而且代码的可读性和可维护性大幅提升。如果现在要新增“企业用户策略”,只需做3件事:

  1. 新建EnterpriseUserStrategy类,继承DiscountStrategy并实现接口;

  2. 在客户端调用setStrategy(new EnterpriseUserStrategy())

  3. 无需修改任何原有代码。

这就是策略模式带来的优势——扩展开放,修改关闭

四、策略模式进阶:优化与扩展技巧

前面的实现已经满足了基本需求,但在实际开发中,我们还可以对策略模式进行优化,让代码更优雅、更符合C++的特性。

1. 用智能指针替代裸指针,避免内存泄漏

前面的上下文类中,我们用裸指针持有策略对象,需要手动管理内存,容易出现遗漏析构或重复析构的问题。C++11及以后的版本中,推荐使用智能指针(如unique_ptr)来自动管理内存,彻底避免内存泄漏。

优化后的上下文类核心代码:

#include <memory>  // 包含智能指针头文件

class OrderContext {
public:
    // 构造函数:默认使用普通用户策略
    OrderContext() : strategy(make_unique<NormalUserStrategy>()) {}
    
    // 无需手动写析构函数,unique_ptr会自动释放资源
    
    // 设置策略:接收unique_ptr,转移所有权
    void setStrategy(unique_ptr<DiscountStrategy> newStrategy) {
        if (!newStrategy) {
            cout << "策略不能为空!" << endl;
            return;
        }
        strategy = move(newStrategy);  // 转移智能指针的所有权
    }
    
    // 计算最终金额(逻辑不变)
    double calculateFinalAmount(double amount, const StrategyParams& params) {
        // ... 原有逻辑不变,只需将strategy->改为strategy->即可
    }
private:
    unique_ptr<DiscountStrategy> strategy;  // 智能指针替代裸指针
};

// 客户端调用方式修改
int main() {
    // 场景2:VIP用户,节日活动期间
    OrderContext order2;
    // 用make_unique创建智能指针,无需手动delete
    order2.setStrategy(make_unique<VipUserStrategy>());
    // ... 其他逻辑不变
}

使用unique_ptr后,我们无需手动释放策略对象,智能指针会在上下文对象销毁时自动释放资源,代码更安全、更简洁。

2. 结合工厂模式,解决策略选择问题

在前面的客户端代码中,策略的选择需要客户端手动创建策略对象(如new VipUserStrategy()),如果策略类型很多,客户端需要了解所有策略的类名,增加了客户端的负担。

这时可以结合简单工厂模式,将策略的创建逻辑封装在工厂类中,客户端只需传入策略类型(如字符串“vip”),工厂就会返回对应的策略对象。

// 策略工厂类:封装策略的创建逻辑
class StrategyFactory {
public:
    // 根据用户类型创建对应的策略
    static unique_ptr<DiscountStrategy> createStrategy(const string& userType) {
        if (userType == "normal") {
            return make_unique<NormalUserStrategy>();
        } else if (userType == "vip") {
            return make_unique<VipUserStrategy>();
        } else if (userType == "super_vip") {
            return make_unique<SuperVipUserStrategy>();
        } else {
            cout << "未知用户类型,使用默认普通用户策略" << endl;
            return make_unique<NormalUserStrategy>();
        }
    }
};

// 客户端调用优化
int main() {
    // 场景3:超级会员生日月,无节日活动
    OrderContext order3;
    // 只需传入用户类型字符串,无需手动创建策略对象
    order3.setStrategy(StrategyFactory::createStrategy("super_vip"));
    StrategyParams params3 = {true, false, false, "super_vip"};
    double final3 = order3.calculateFinalAmount(300.0, params3);
    cout << "场景3最终金额:" << final3 << endl;
}

通过工厂模式,客户端与具体策略类解耦,无需知道策略类的具体实现,只需关注策略类型即可。如果新增策略,只需修改工厂类的createStrategy方法,符合“单一职责原则”。

3. 策略模式与模板方法模式的区别

很多初学者会把策略模式和模板方法模式搞混,因为它们都用于处理算法的封装与替换。但两者的核心思想有本质区别:

对比维度

策略模式

模板方法模式

核心思想

算法的“替换”:不同算法是独立的,可完全替换

算法的“定制”:固定算法骨架,只定制其中部分步骤

实现方式

组合关系(上下文持有策略对象)

继承关系(子类继承父类模板)

灵活性

高,可动态切换策略

低,策略固定在子类中,无法动态切换

适用场景

算法之间独立,需要动态切换

算法有固定流程,只需定制部分步骤

举个通俗的例子:如果把“做咖啡”看作一个算法,策略模式就是“用手冲、用咖啡机、用速溶粉”三种完全不同的方法,可随时切换;而模板方法模式是“煮水→加咖啡→加调料”的固定流程,子类只需定制“加什么调料”(糖或奶)。

五、策略模式的优缺点与适用场景

没有完美的设计模式,只有适合的设计模式。在使用策略模式之前,我们需要清楚它的优缺点,判断是否符合当前的业务场景。

1. 优点

  1. 符合开闭原则:新增策略只需新增类,无需修改原有代码,扩展灵活;

  2. 消除分支冗余:用策略的动态切换替代if-else/switch分支,代码更简洁,可读性更高;

  3. 算法独立可复用:每个策略都是独立的类,可在不同模块中复用(比如折扣策略可用于订单模块和优惠券模块);

  4. 便于测试:每个策略独立,可单独编写单元测试,测试效率更高;

  5. 动态切换策略:通过上下文的setStrategy方法,可在运行时动态切换策略,适应不同业务场景。

2. 缺点

  1. 增加类的数量:每个策略对应一个类,策略越多,类的数量越多,可能导致“类爆炸”;

  2. 客户端需了解策略:客户端需要知道有哪些策略,才能选择合适的策略(可通过工厂模式缓解);

  3. 适合复杂场景:如果策略很少且变化不频繁,使用策略模式反而会增加代码复杂度,不如直接用分支。

3. 适用场景

当你的代码符合以下特征时,就可以考虑使用策略模式:

  • 代码中存在大量if-else/switch分支,且分支对应不同的业务逻辑;

  • 业务逻辑中有多种算法,且算法之间可以相互替换;

  • 需要动态切换算法,以适应不同的业务场景(比如支付方式切换、日志输出方式切换);

  • 希望代码符合开闭原则,便于后续扩展(比如电商的折扣规则、快递的计价规则)。

六、实际开发中的策略模式应用案例

策略模式在实际开发中应用非常广泛,以下是几个常见的场景,帮助你更好地理解它的价值:

1. 支付系统

支付系统支持支付宝、微信支付、银行卡支付、Apple Pay等多种支付方式,每种支付方式的调用接口、签名规则、回调处理都不同。用策略模式可以将每种支付方式封装成一个策略类,上下文类负责统一调用,新增支付方式时只需新增策略类。

2. 日志系统

日志系统需要支持不同的日志输出方式:控制台输出、文件输出、数据库存储、远程日志服务。每种输出方式的实现逻辑不同,用策略模式可以动态切换日志输出方式(比如开发环境输出到控制台,生产环境输出到文件和远程服务)。

3. 排序算法

排序算法有冒泡排序、快速排序、归并排序、堆排序等,不同算法的时间复杂度和空间复杂度不同,适用于不同的数据规模。用策略模式可以根据数据规模动态选择排序算法(比如小规模数据用冒泡排序,大规模数据用快速排序)。

4. 表单验证

表单验证需要对不同的字段进行不同的验证规则:手机号验证(格式)、密码验证(长度+复杂度)、邮箱验证(格式)、身份证号验证(格式+校验位)。用策略模式可以将每种验证规则封装成策略类,上下文类负责统一执行验证。

七、总结:策略模式的核心价值

策略模式的核心价值,在于解耦“算法的定义”与“算法的使用”。它让变化的逻辑(策略)和稳定的逻辑(上下文)分离开来,既保证了代码的整洁性,又提升了扩展的灵活性。

回顾咱们的电商折扣案例,从最初的“分支地狱”到重构后的“策略化代码”,我们不仅解决了当前的业务问题,还为后续的扩展铺平了道路。这就是设计模式的魅力——它不是炫技的工具,而是解决实际问题的“工程思想”。

最后提醒大家:设计模式不是“银弹”,不要为了用设计模式而用设计模式。在实际开发中,我们需要结合业务复杂度、团队协作习惯、未来的扩展需求等因素,综合判断是否使用策略模式。但当你再次遇到“分支冗余”的问题时,不妨试试策略模式,相信它会给你带来不一样的代码体验。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值