一、业务场景
项目需要对接支付系统,根据不同客户类型会有不同的支付方式,比如:支付宝、微信、银联、云闪付等等其他第三方支付平台,这个时候策略模式就大展身手了。
传统的if/else/switch 等等判断的写法太low了,代码糅合在一块,维护也不方便。
二、简单代码示例
1、实体类准备
订单信息类
package com.iot.designpattern.strategy.model;
import lombok.Data;
import lombok.experimental.Accessors;
/**
* 订单信息
*
*/
@Data
@Accessors(chain = true)
public class Order {
/**
* 金额
*/
private int amount;
/**
* 支付类型
*/
private String type;
}
返回结果类
package com.iot.designpattern.strategy.model;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* 支付结果
*
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class PayResult {
/**
* 响应码
*/
private int code;
/**
* 提示信息
*/
private String msg;
public static PayResult success(String msg) {
return new PayResult(200, msg);
}
}
2、定义策略接口(所有支付方式的接口),策略接口如下:
package com.iot.designpattern.strategy.service;
import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;
/**
* 支付接口
*
*/
public interface IPayment {
/**
* 支付
*
* @param order 订单信息
* @return PayResult 支付结果
*/
PayResult pay(Order order);
}
3、定义各种策略实现类
支付宝支付实现类:
package com.iot.designpattern.strategy.service.Impl;
import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;
import com.iot.designpattern.strategy.service.IPayment;
import org.springframework.stereotype.Service;
/**
* 支付宝支付
*
*/
@Service
public class AliPay implements IPayment {
@Override
public PayResult pay(Order order) {
return new PayResult(200, "支付宝支付成功");
}
}
微信支付实现类:
package com.iot.designpattern.strategy.service.Impl;
import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;
import com.iot.designpattern.strategy.service.IPayment;
import org.springframework.stereotype.Service;
/**
* 微信支付
*
*/
@Service
public class WechatPay implements IPayment {
@Override
public PayResult pay(Order order) {
return new PayResult(200, "微信支付成功");
}
}
银联支付实现类:
package com.iot.designpattern.strategy.service.Impl;
import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;
import com.iot.designpattern.strategy.service.IPayment;
import org.springframework.stereotype.Service;
/**
* 银联支付
*
*/
@Service
public class UnionPay implements IPayment {
@Override
public PayResult pay(Order order) {
System.out.println("开始银联支付");
return PayResult.success("银联支付成功");
}
}
注:通过@Service注解将支付实现类注入spring工厂管理,默认bean名字是类名(开头小写)
4、使用策略
package com.iot.designpattern.strategy.controller;
import com.iot.designpattern.strategy.model.Order;
import com.iot.designpattern.strategy.model.PayResult;
import com.iot.designpattern.strategy.service.IPayment;
import lombok.AllArgsConstructor;
import org.springframework.context.ApplicationContext;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 支付
*
*/
@RestController
@AllArgsConstructor
@RequestMapping("/pay/")
public class PayController {
private final ApplicationContext applicationContext;
/**
* 支付API
*
* @param amount 金额
* @param payType 支付类型
* @return PayResult
*/
@GetMapping()
public PayResult pay(int amount, String payType) {
Order order = new Order().setAmount(amount).setType(payType);
// 根据【支付类型】获取对应的策略 bean
IPayment payment = applicationContext.getBean(payType, IPayment.class);
// 开始调用策略对应的支付业务逻辑
return payment.pay(order);
}
}
5、测试一下:
注:在调用的时候,注意payType中值为@Service对应的类名(开头小写),也可以自己在注解中命名name
微信:
![image.png](https://ucc.alicdn.com/pic/developer-ecology/hk2sott5ojhdm_35381a4b640f48c8a77821bc7458e124.png)
支付宝:
![image.png](https://ucc.alicdn.com/pic/developer-ecology/hk2sott5ojhdm_d73130a4a4d044329611b94d721081f6.png)
银联:
![image.png](https://ucc.alicdn.com/pic/developer-ecology/hk2sott5ojhdm_7cfbc34799834d91b489e92dbb02754b.png)
三、总结
使用策略模式,我们可以干掉大量的if/else,代码也更优雅,还能灵活扩展。像本文中的支付案例,后面如果有别的支付方式,我们只需要写一个新的对应支付实现类即可,无需修改现有代码。
当然,完全干掉if/else是不可能的,不能过度设计,不能为了使用设计模式而使用设计模式。
策略模式的优点:
干掉繁琐的if、switch判断逻辑;
代码优雅、可服用、可读性好;
符合开闭原则、扩展性好、便于维护;
策略模式的缺点:
策略如果很多的话,会造成策略类膨胀;
使用者必须清楚所有的策略类及其用途;