告别通勤选择困难症——策略模式
- 一、传统实现的痛点:if-else 的泥潭
- 二、策略模式的解法:模块化拆分
- 三、优势对比:策略模式的价值
- 四、应用场景与边界
- 五、设计启示
引子:一个程序员的通勤顿悟时刻
周一清晨,程序员小张盯着手机里的三条提醒发愁:
① 天气App:今日有暴雨⛈️(降水概率90%)
② 导航App:常走路线拥堵1.5公里🚗
③ 健康手环:建议完成30分钟有氧运动🏃
他的大脑开始条件反射式地处理这些输入参数:
// 传统if-else思维模式
if (天气 == 暴雨) {呼叫网约车();
} else if (拥堵距离 > 1公里) {启动地铁方案();
} else if (需要运动) {选择共享单车();
} else {默认自驾方案();
}
突然意识到:每新增一个决策因素(如油价上涨、地铁限流),就要在代码里插入新的else if,就像在已经打结的耳机线上再绕一圈。这促使他思考——是否有更优雅的解决方案?
一、传统实现的痛点:if-else 的泥潭
假设我们需要实现通勤方案选择功能,传统写法通常是这样的:
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}
}
传统代码的三大痛点:
- 代码臃肿:当交通工具增加到10种时,方法长度超过100行
- 修改风险:新增或修改某种交通方式时可能影响其他逻辑
- 难以复用:耗时计算与执行逻辑耦合在一起
二、策略模式的解法:模块化拆分
策略模式三要素:
- 策略接口(Strategy Interface):定义算法族的统一规范。声明所有具体策略必须实现的方法
- 具体策略实现(Concrete Strategies):封装具体算法实现。每个类独立实现接口方法,包含特定业务逻辑
- 上下文环境(Context):策略调度与执行协调。持有策略对象的引用,将客户端请求委派给具体策略
// 策略接口(规范)
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();}
}
客户端调用:
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) 每个策略类只负责一种算法实现
当你在编写充满条件判断的业务代码时,不妨思考:这些逻辑是否可以被抽象为一系列可插拔的策略对象?
这正是策略模式给我们的最佳实践启示。