编辑
2025-08-11
知识储备-设计模式
00
请注意,本文编写于 126 天前,最后修改于 126 天前,其中某些信息可能已经过时。

目录

为什么资深Java开发都爱用策略模式?
一、被if-else支配的恐惧:
二、策略模式到底是啥?
三、实战案例:

为什么资深Java开发都爱用策略模式?

一、被if-else支配的恐惧:

我曾踩过的代码坑记得刚接手一个电商项目时,看到支付模块的代码直接懵了——几百行的if-else嵌套,从信用卡支付到三方平台接口,每个条件分支都塞满了逻辑。

最崩溃的是,当产品说"要新增一个跨境支付方式"时,我盯着屏幕半小时不敢下手:改现有逻辑怕影响线上,新增分支又怕代码膨胀成面条。

后来在大佬的指点下用策略模式重构,才发现原来代码可以这么清爽。举个栗子:原本判断用户折扣的代码是这样的:

if (userType == "普通会员") { price = price * 0.9; } else if (userType == "黄金会员") { price = price * 0.8; // 后来又加了铂金会员、钻石会员... } else if (userType == "特邀会员") { price = price * 0.7 + 优惠券抵扣; }

每次新增会员等级都像在雷区跳舞,直到用策略模式把每个折扣规则拆成独立类,才真正体会到"开闭原则"的魅力——新增策略时只要写个新类,原来的代码一行都不用改。

二、策略模式到底是啥?

用快递发货打个比方其实策略模式的核心思想特别接地气。

就像你寄快递时,不同场景会选不同物流:寄急件选顺丰,大件选德邦,便宜货选四通一达。

策略模式就是把这些"发货策略"封装起来,让系统能根据条件动态选择,而不用在代码里写死"如果是急件就选顺丰,否则选...".

在代码里,这个过程分为三步:

定义策略接口:比如ShippingStrategy接口里有个deliver()方法

实现具体策略:SFExpressStrategy、STExpressStrategy等类各自实现发货逻辑

上下文调度:ShippingService根据订单类型调用对应的策略在Spring Boot里集成更方便,靠依赖注入就能把策略塞进上下文里。

我常用的一个技巧是:在策略类上用@Component("sfExpress")这样的注解,然后在上下文里通过Map<String, ShippingStrategy>直接获取,键名就是注解里的字符串,比硬编码if-else爽太多。

三、实战案例:

从混乱到优雅的支付系统重构之前负责的一个跨境电商项目,支付模块支持信用卡、PayPal、本地钱包等七八种方式。

最初的代码是这样的:

if ("creditCard".equals(paymentType)) { // 信用卡支付逻辑,包括3D验证、风控检查... } else if ("paypal".equals(paymentType)) { // PayPal的授权流程,还要处理异步回调... } else if ("localWallet".equals(paymentType)) { // 本地钱包的特殊加密处理... }

每次新增支付方式都要改这个大条件块,更头疼的是单元测试——想测PayPal支付得把整个条件链跑一遍。

后来用策略模式重构:

1.定义支付策略接口

public interface PaymentStrategy { boolean process(PaymentRequest request); }

2.每个支付方式一个策略类

@Component("creditCard") public class CreditCardStrategy implements PaymentStrategy { @Override public boolean process(PaymentRequest request) { // 专注写信用卡支付逻辑,代码量减少60% } }

3.上下文类用Map管理策略

@Service publicclass PaymentService { privatefinal Map<String, PaymentStrategy> strategyMap; @Autowired public PaymentService(Map<String, PaymentStrategy> strategies) { this.strategyMap = strategies; } public boolean pay(PaymentType type, PaymentRequest request) { PaymentStrategy strategy = strategyMap.get(type.name().toLowerCase()); return strategy.process(request); } }

重构后最明显的变化:

新增支付方式时,我只需要写一个新策略类,然后在枚举里加个类型,原来的PaymentService一行都不用动。

测试也变得简单,每个策略类可以单独测,再也不用为了测一个分支跑通整个条件链了。

四、策略模式的隐藏技巧:

Lambda和Spring的神仙组合当策略逻辑比较简单时,甚至可以不用写一堆类。比如计算不同国家的税费,用Java 8的Lambda能把代码缩到极致:

// 在配置类里定义策略Map @Bean public Map<String, Function<Double, Double>> taxStrategyMap() { return Map.of( "CN", amount -> amount * 0.13,  // 中国增值税 "US", amount -> amount * 0.07,  // 美国销售税 "JP", amount -> amount * 0.10   // 日本消费税 ); } // 在服务里直接用 @Service publicclass TaxService { privatefinal Map<String, Function<Double, Double>> strategyMap; @Autowired public TaxService(Map<String, Function<Double, Double>> strategyMap) { this.strategyMap = strategyMap; } public double calculate(String country, double amount) { return strategyMap.get(country).apply(amount); } }

这种写法特别适合没有复杂状态的策略,比如计算规则、汇率转换等,既能享受策略模式的灵活性,又不用写一堆类,简直是懒癌患者的福音。

五、什么时候别用策略模式?

过来人的避坑指南虽然策略模式很香,但也不是万能药。我踩过的坑包括:

小场景别过度设计:如果只有两三种条件判断,比如"是管理员就显示全部按钮,否则显示部分",直接用if-else更直观

有状态的策略要小心:如果策略里需要维护全局状态(比如计数器),多个策略共享时可能出线程安全问题

Spring注入的坑:曾经忘记在策略类上加@Component,结果上下文获取时报空指针,debug半天才发现

还有个小技巧:当策略类很多时,可以用自定义注解来分组。比如我在项目里定义了@PaymentStrategy注解,然后在上下文里通过@Autowired注入List,再结合策略类上的@Order注解排序,比用Map更灵活。

六、从工具到思维:策略模式带来的架构思维升级

刚开始用策略模式时,只是觉得它能干掉讨厌的if-else。但随着项目经验增多,慢慢体会到它背后的设计哲学:把变化的部分封装成可替换的组件,让不变的逻辑保持稳定。

这种思维不仅适用于代码,也适用于架构设计——比如微服务里的路由策略、网关的限流策略,本质上都是策略模式的应用。

现在看到项目里出现超长的条件链,我第一反应就是:这里能不能用策略模式?当产品提出"以后可能会支持XX功能"时,也会下意识地用策略模式预留扩展点。这种思维方式的转变,可能比具体的代码技巧更有价值。

最后想说策略模式不是什么高深的黑魔法,而是从无数次代码维护痛苦中提炼出的解决方案。

它教会我们:好的代码不仅要能跑,还要能优雅地应对变化。下次当你面对满屏的if-else无从下手时,不妨试试策略模式——说不定会打开新世界的大门。

本文作者:Allen Tang

本文链接:

版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!