告别通勤选择困难症——策略模式

告别通勤选择困难症------策略模式

引子:一个程序员的通勤顿悟时刻

周一清晨,程序员小张盯着手机里的三条提醒发愁:

① 天气App:今日有暴雨⛈️(降水概率90%)

② 导航App:常走路线拥堵1.5公里🚗

③ 健康手环:建议完成30分钟有氧运动🏃

他的大脑开始条件反射式地处理这些输入参数:

java 复制代码
// 传统if-else思维模式
if (天气 == 暴雨) {
    呼叫网约车();
} else if (拥堵距离 > 1公里) {
    启动地铁方案();
} else if (需要运动) {
    选择共享单车();
} else {
    默认自驾方案();
}

突然意识到:每新增一个决策因素(如油价上涨、地铁限流),就要在代码里插入新的else if,就像在已经打结的耳机线上再绕一圈。这促使他思考------是否有更优雅的解决方案?

一、传统实现的痛点:if-else 的泥潭

假设我们需要实现通勤方案选择功能,传统写法通常是这样的:

java 复制代码
public class CommuteService {
    public void chooseTransport(String type, int distance) {
        if ("bike".equals(type)) {
            System.out.println("骑行方案:");
            int time = (int)(distance / 12.0 * 60);
            System.out.println("预计耗时:" + time + "分钟");
            System.out.println("执行操作:扫码开锁 → 规划骑行路线");
        } else if ("subway".equals(type)) {
            System.out.println("地铁方案:");
            int time = (distance / 2) * 4 + 10;
            System.out.println("预计耗时:" + time + "分钟");
            System.out.println("执行操作:选择换乘路线 → 安检进站");
        } else if ("car".equals(type)) {
            System.out.println("自驾方案:");
            int time = (int)(distance / 30.0 * 60) + 15;
            System.out.println("预计耗时:" + time + "分钟");
            System.out.println("执行操作:导航避开限行 → 寻找停车位");
        }
        // 每新增一种方式就要添加else-if
    }
}

传统代码的三大痛点

  1. 代码臃肿:当交通工具增加到10种时,方法长度超过100行
  2. 修改风险:新增或修改某种交通方式时可能影响其他逻辑
  3. 难以复用:耗时计算与执行逻辑耦合在一起

二、策略模式的解法:模块化拆分

策略模式三要素:

  • 策略接口(Strategy Interface):定义算法族的统一规范。声明所有具体策略必须实现的方法
  • 具体策略实现(Concrete Strategies):封装具体算法实现。每个类独立实现接口方法,包含特定业务逻辑
  • 上下文环境(Context):策略调度与执行协调。持有策略对象的引用,将客户端请求委派给具体策略
java 复制代码
// 策略接口(规范)
interface TransportStrategy {
    int calculateTime(int distance);
    void execute();
}

// 具体策略实现
class BikeStrategy implements TransportStrategy {
    public int calculateTime(int distance) {
        return (int)(distance / 12.0 * 60);
    }
    public void execute() {
        System.out.println("扫码开锁 → 规划骑行路线");
    }
}

class SubwayStrategy implements TransportStrategy {
    public int calculateTime(int distance) {
        return (distance / 2) * 4 + 10;
    }
    public void execute() {
        System.out.println("选择换乘路线 → 安检进站");
    }
}

// 上下文环境
class CommuteContext {
    private TransportStrategy strategy;
    
    public void setStrategy(TransportStrategy strategy) {
        this.strategy = strategy;
    }
    
    public void startCommute(int distance) {
        System.out.println("预计耗时:" + strategy.calculateTime(distance) + "分钟");
        strategy.execute();
    }
}

客户端调用:

java 复制代码
public class Client {
    public static void main(String[] args) {
        CommuteContext context = new CommuteContext();
        
        // 动态切换策略
        context.setStrategy(new BikeStrategy());
        context.startCommute(10);  // 骑行10公里
        
        context.setStrategy(new SubwayStrategy());
        context.startCommute(15);  // 地铁15公里
    }
}

三、优势对比:策略模式的价值

传统if-else实现 策略模式实现
代码可读性 逻辑混杂,难以快速定位 模块清晰,每个策略独立文件
扩展成本 修改原文件,风险高 新增类即可,符合开闭原则
单元测试 需要覆盖所有分支 可单独测试每个策略
业务复用 逻辑无法复用 策略可跨场景复用(如配送系统)

扩展逻辑:

当需要新增「电动车」方案时:

  • 传统方式:在原有方法中增加else if ("escooter".equals(type))分支
  • 策略模式:创建EscooterStrategy类并实现接口即可

四、应用场景与边界

推荐使用场景:

  • 算法族需要自由切换(如加密算法、压缩算法)
  • 存在相似但不同的业务规则(如不同地区的税费计算)
  • 需要消除多层条件判断(超过3层的if-else)

不适用场景:

  • 简单且固定的业务逻辑(如单一算法场景)
  • 策略之间强耦合的场景(如必须先执行A策略才能执行B)

五、设计启示

策略模式体现了两个重要的设计原则:

  • 开闭原则(OCP) 对扩展开放(新增策略),对修改关闭(不改变上下文)
  • 单一职责原则(SRP) 每个策略类只负责一种算法实现

当你在编写充满条件判断的业务代码时,不妨思考:这些逻辑是否可以被抽象为一系列可插拔的策略对象?

这正是策略模式给我们的最佳实践启示。

相关推荐
十五年专注C++开发1 小时前
QT 中的元对象系统(五):QMetaObject::invokeMethod的使用和实现原理
开发语言·数据结构·c++·qt·设计模式
nlog3n7 小时前
Java策略模式详解
java·bash·策略模式
rainFFrain7 小时前
日志与策略模式
linux·运维·vscode·策略模式
shuaixio11 小时前
【C++代码整洁之道】第九章 设计模式和习惯用法
c++·设计模式·设计原则·常见设计模式·习惯用法
南宫生11 小时前
Java迭代器【设计模式之迭代器模式】
java·学习·设计模式·kotlin·迭代器模式
程序员小赵同学12 小时前
AI Agent设计模式二:Parallelization
开发语言·python·设计模式
千千寰宇12 小时前
[设计模式/Java] 设计模式之工厂方法模式【11】
设计模式
此木|西贝13 小时前
【设计模式】模板方法模式
java·设计模式·模板方法模式
编程侦探15 小时前
【设计模式】原型模式:用“克隆”术让对象创建更灵活
c++·设计模式·原型模式