目录
种一棵树最好的时间是10年前,其次就是现在,加油!
--by蜡笔小柯南
开篇
当新需求像野生的波波雀不断飞来,你的代码却还在用 if-else的精灵球硬抓?当代码中充斥着大量的if-else,if-else的数量随着每一次的更新迭代,都越来越多,越来越难以维护,可读性越来越差。那么,有没有什么办法可以解决这个问题呢,答案是:有的,那就是使用设计模式中的----策略模式!
什么是策略模式
策略模式就像 「冰淇淋机」,投币选择「草莓/巧克力/抹茶」模式,就能产出对应口味—— 无需改造机器内部结构,轻松更换算法。
也就是说,在使用策略模式后,新增策略无需修改核心类,只需增加策略的扩展类即可,大大降低代码的耦合,以及使代码有更好的维护性和扩展性。
代码实战
if-else模式
Controller层代码
@RestController
@RequestMapping("/order")
public class PayController {
@Autowired
private PayService payService;
@PostMapping("/pay")
public String pay(@RequestBody Order order) {
return payService.pay(order);
}
}
Service层代码
public interface PayService {
String pay(Order order);
}
@Service
public class PayServiceImpl implements PayService{
@Override
public String pay(Order order) {
// 模拟处理订单逻辑
System.out.println("订单已处理,开始支付...");
if ("wechat".equals(order.getPayType())) {
System.out.println("微信支付");
} else if ("alipay".equals(order.getPayType())) {
System.out.println("支付宝支付");
} else if ("unionpay".equals(order.getPayType())) {
System.out.println("银联支付");
}
// 支付成功,其他后续处理
System.out.println("支付成功,其他后续处理...");
return "支付成功";
}
}
实体类
@Data
public class Order {
/**
* 订单id
*/
private Long id;
/**
* 订单金额
*/
private BigDecimal money;
/**
* 支付方式
*/
private String payType;
}
根据不同的payType参数,分别选择不同的支付方式
如果我们后续需要支持其他的支付方式,就需要修改PayServiceImpl中的代码,增加对其他支付方式的支持,如:要增加支持白条支付和信用卡支付,代码修改如下:
@Service
public class PayServiceImpl implements PayService{
@Override
public String pay(Order order) {
// 模拟处理订单逻辑
System.out.println("订单已处理,开始支付...");
if ("wechat".equals(order.getPayType())) {
System.out.println("微信支付");
} else if ("alipay".equals(order.getPayType())) {
System.out.println("支付宝支付");
} else if ("unionpay".equals(order.getPayType())) {
System.out.println("银联支付");
} else if ("baitiao".equals(order.getPayType())) {
System.out.println("白条支付");
} else if ("credit".equals(order.getPayType())) {
System.out.println("信用卡支付");
}
// 支付成功,其他后续处理
System.out.println("支付成功,其他后续处理...");
return "支付成功";
}
}
每增加一种支付方式,就得修改代码逻辑,增加一层if-else,久而久之,代码会变得非常臃肿,if-else也会越来越多。
接下来,我们使用策略模式,来对比一下两者的区别
策略模式
增加枚举类,用于配置支付的方式
@Getter
public enum PayTypeEnum {
WECHAT("wechat", "微信支付"),
ALIPAY("alipay", "支付宝支付"),
UNIONPAY("unionpay", "银联支付");
private String code;
private String desc;
PayTypeEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
public static PayTypeEnum getByCode(String code) {
for (PayTypeEnum payTypeEnum : PayTypeEnum.values()) {
if (payTypeEnum.getCode().equals(code)) {
return payTypeEnum;
}
}
return null;
}
}
增加支付策略接口,定义两个方法
- getPayType:获取支付方式所对应的枚举
- pay:实际的支付方法
public interface PayStrategy {
PayTypeEnum getPayType();
String pay();
}
分别为不同的支付方式,创建对应的策略实现类
微信支付策略
@Service
public class WechatStrategyImpl implements PayStrategy {
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.WECHAT;
}
@Override
public void pay() {
System.out.println("微信支付...");
}
}
支付宝支付策略
@Service
public class AlipayStrategyImpl implements PayStrategy {
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.ALIPAY;
}
@Override
public void pay() {
System.out.println("支付宝支付...");
}
}
银联支付策略
@Service
public class UnionpayStrategyImpl implements PayStrategy{
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.UNIONPAY;
}
@Override
public void pay() {
System.out.println("银联支付...");
}
}
为所有的支付方式策略提供一个入口,如:我们这里命名为:PayStrategyFactory,通过它来获取不同支付方式的策略实现类(微信支付策略、支付宝支付策略、银联支付策略),用于真正的支付逻辑
@Component
public class PayStrategyFactory {
@Autowired
private List<PayStrategy> payStrategyList;
public PayStrategy getPayStrategy(String payType) {
return payStrategyList.stream().filter(item -> item.getPayType().getCode().equals(payType)).findFirst().orElse(null);
}
}
修改PayServiceImpl类,如下
@Service
public class PayServiceImpl implements PayService {
@Autowired
private PayStrategyFactory payStrategyFactory;
@Override
public String pay(Order order) {
// 模拟处理订单逻辑
System.out.println("订单已处理,开始支付...");
// 从策略工厂获取支付策略
PayStrategy payStrategy = payStrategyFactory.getPayStrategy(order.getPayType());
if (payStrategy == null) {
throw new RuntimeException("不支持的支付类型");
}
// 执行支付
payStrategy.pay();
// 支付成功,其他后续处理
System.out.println("支付成功,其他后续处理...");
return "支付成功";
}
}
测试
微信支付
设置payType为wechat,发送请求

控制台打印的数据

支付宝支付
设置payType为alipay,发送请求

控制台打印的数据

银联支付
设置payType为unionpay,发送请求

控制台打印的数据

根据 payType 参数的不同,自动使用不同的支付方式
策略模式的优点
策略模式的优点是,在后续更新迭代的过程中,核心代码类保持不变,只是根据所需进行相应的扩展。不影响原有逻辑,低耦合,扩展性好。
如果,我们想要增加一种新的支付方式,白条支付,PayServiceImpl 核心支付类无需修改,只需要增加一个新的类,并在枚举类中定义新的支付方式(使用枚举类是为了管理常量方便,以便在后续获取支付策略的实现类时方便使用公共的常量),实现PayStrategy接口,重写对应的方法即可。
后续如果要再增加其他的支付方式,就再建一个新的类,实现PayStrategy接口,重写对应的方法,其他代码全部不用修改。
在 PayTypeEnum 新增支付方式
@Getter
public enum PayTypeEnum {
WECHAT("wechat", "微信支付"),
ALIPAY("alipay", "支付宝支付"),
UNIONPAY("unionpay", "银联支付"),
BAI_TIAO("baitiao", "白条支付");
private String code;
private String desc;
PayTypeEnum(String code, String desc) {
this.code = code;
this.desc = desc;
}
public static PayTypeEnum getByCode(String code) {
for (PayTypeEnum payTypeEnum : PayTypeEnum.values()) {
if (payTypeEnum.getCode().equals(code)) {
return payTypeEnum;
}
}
return null;
}
}
新建名为 BaiTiaoStrategy 的类,实现 PayStrategy,getPayType 方法指定白条支付方式,pay 方法是具体白条支付的逻辑,这里我们简单打印白条支付
@Service
public class BaiTiaoStrategyImpl implements PayStrategy {
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.BAI_TIAO;
}
@Override
public void pay() {
System.out.println("白条支付");
}
}
完成这两步,在请求时,将 payType 设置为 baitiao,即能切换到白条支付


代码详解
PayStrategy
定义支付策略的接口,支付方式:getPayType ,支付方法:pay
public interface PayStrategy {
PayTypeEnum getPayType();
void pay();
}
WechatStrategyImpl
实现 PayStrategy 接口,重写接口中定义的方法,并在 getPayType 方法中,指定微信支付
@Service
public class WechatStrategyImpl implements PayStrategy {
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.WECHAT;
}
@Override
public void pay() {
System.out.println("微信支付...");
}
}
AlipayStrategyImpl
实现 PayStrategy 接口,重写接口中定义的方法,并在 getPayType 方法中,指定支付宝支付
@Service
public class AlipayStrategyImpl implements PayStrategy {
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.ALIPAY;
}
@Override
public void pay() {
System.out.println("支付宝支付...");
}
}
UnionpayStrategyImpl
实现 PayStrategy 接口,重写接口中定义的方法,并在 getPayType 方法中,指定银联支付
@Service
public class UnionpayStrategyImpl implements PayStrategy{
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.UNIONPAY;
}
@Override
public void pay() {
System.out.println("银联支付...");
}
}
BaiTiaoStrategyImpl
实现 PayStrategy 接口,重写接口中定义的方法,并在 getPayType 方法中,指定白条支付
@Service
public class BaiTiaoStrategyImpl implements PayStrategy {
@Override
public PayTypeEnum getPayType() {
return PayTypeEnum.BAI_TIAO;
}
@Override
public void pay() {
System.out.println("白条支付");
}
}
PayStrategyFactory
可以看作是一个获取支付策略的工厂类,或是一个入口,通过此类,来获取具体的支付类。
根据前端传入的 payType 参数,如果传入的是 wechat ,就获取 WechatStrategyImpl 来处理;如果传入的是 alipay ,就获取 AlipayStrategyImpl 来处理,以此类推。
其中,注入了 PayStrategy 的一个List集合
@Autowired
private List<PayStrategy> payStrategyList;
在Spring中,我们大多常见的是,注入一个单个的实例,而不是List类型的,如:
@Autowired
private PayStrategy payStrategy;
其实在Spring中,还有这样一个特性,如果我们使用List集合的方式,,且泛型中写的是接口,那么,在注入时,这个接口所有的实现类都会被注入进来。
在这个例子中,PayStrategy 是接口,实现类有:WechatStrategyImpl、AlipayStrategyImpl、UnionpayStrategyImpl、BaiTiaoStrategyImpl ,一共4个,也就是说,在注入时,这个List中,保存的就是这4个实现类
方法 getPayStrategy 用于获取对应支付方式 payType 的支付策略类,就是根据 payType 从List中的4个实现类中,找出满足条件的那个。
如果 payType 是 wechat ,就获取 WechatStrategyImpl
如果 payType 是 alipay ,就获取 AlipayStrategyImpl
如果 payType 是 unionpay ,就获取 UnionpayStrategyImpl
如果 payType 是 baitiao ,就获取 BaiTiaoStrategyImpl
public PayStrategy getPayStrategy(String payType) {
return payStrategyList.stream().filter(item -> item.getPayType().getCode().equals(payType)).findFirst().orElse(null);
}
此处是使用 Stream 流的方式,如果不熟悉这种方式,可以使用普通的for循环,如下:
public PayStrategy getPayStrategy(String payType) {
for (PayStrategy payStrategy : payStrategyList) {
if (payStrategy.getPayType().getCode().equals(payType)) {
return payStrategy;
}
}
return null;
}
在 PayServiceImpl 类中注入 PayStrategyFactory
@Autowired
private PayStrategyFactory payStrategyFactory;
核心处理代码
// 从策略工厂获取支付策略
PayStrategy payStrategy = payStrategyFactory.getPayStrategy(order.getPayType());
if (payStrategy == null) {
throw new RuntimeException("不支持的支付类型");
}
// 执行支付
payStrategy.pay();
根据 payType 获取对应的实现类,执行方法。如:
payType是wechat,获取到的就是WechatStrategyImpl,那么在调用pay()方法时,就是调用的WechatStrategyImpl中的pay()方法,即输出:微信支付。
payType是alipay,获取到的就是AlipayStrategyImpl,那么在调用pay()方法时,就是调用的AlipayStrategyImpl中的pay()方法,即输出:支付宝支付。
payType是unionpay,获取到的就是UnionpayStrategyImpl,那么在调用pay()方法时,就是调用的UnionpayStrategyImpl中的pay()方法,即输出:银联支付。
payType是baitiao,获取到的就是BaiTiaoStrategyImpl,那么在调用pay()方法时,就是调用的BaiTiaoStrategyImpl中的pay()方法,即输出:白条支付。
这样,完完全全消除了大量的if-else,且后续扩展只需新增类,原有类不再受影响,耦合性大幅度降低。
结尾
1️⃣ 需求进化不慌:当产品经理想再加「其他支付」,只需新建一个其他支付策略 → 即插即用
2️⃣ 战斗零损伤:每个策略相互独立,互不影响,再也不用怕改崩祖传逻辑
3️⃣ 团队协作开挂:新人也能3分钟添加新招式
如果你有任何疑问或经验分享,可以在评论区留言哦~~
不管在任何时候,我希望你永远不要害怕挑战,不要畏惧失败。每一个错误都是向成功迈出的一步,每一个挑战都是成长的机会,因为每一次的努力,都会使我们离梦想更近一点。只要你行动起来,任何时候都不算晚。最后,把座右铭送给大家:种一棵树最好的时间是10年前,其次就是现在,加油!共勉 💪。


被折叠的 条评论
为什么被折叠?



