经典案例:如果我们调用支付方式的支付接口。
java
/**
* @author maoyouhua
* @time 2024/3/18
* @jdkversion jdk21
*
* 调用支付方式
*
* 面临问题:
* 假如我们即将接入新的支付方式,必须修改代码
* 假如后面支付方式接口发生了改变或者替换,也必须修改代码
*
* 这段代码有两个主要问题:
* 一是不符合开闭原则,可以预见
* 二是不符合迪米特法则,发奖逻辑和各个下游接口高度耦合,这导致接口的改变将直接影响到代码的组织,使得代码的可维护性降低
*/
public interface PayService {
void payment(String payType, String params);
}
@Service
class PayServiceImpl implements PayService {
@Override
public void payment(String payType, String params) {
if ("Alipay".equals(payType)) {
System.out.println("调用支付宝支付方式接口");
} else if ("WeChatPay".equals(payType)) {
System.out.println("调用微信支付方式接口");
} else {
throw new IllegalArgumentException("payType error!");
}
}
}
引申出的问题:
假如我们即将接入新的支付方式,必须修改代码。
假如后面支付方式接口发生了改变或者替换,也必须修改代码。
其实不难看出这段代码的问题是:
一是不符合开闭原则,可以预见 。
二是不符合迪米特法则,逻辑和各个支付接口高度耦合,这导致接口的改变将直接影响到代码的组织,使得代码的可维护性降低。
那么可以使用策略模式解决以上的问题,参考美团:设计模式二三事。
策略模式定义了一系列的算法,并将每一个算法封装起来,使它们可以相互替换。策略模式通常包含以下角色: 抽象策略(Strategy)类:定义了一个公共接口,各种不同的算法以不同的方式实现这个接口,环境角色使用这个接口调用不同的算法,一般使用接口或抽象类实现。 具体策略(Concrete Strategy)类:实现了抽象策略定义的接口,提供具体的算法实现。 环境(Context)类:持有一个策略类的引用,最终给客户端调用。
java
/**
* @author maoyouhua
* @time 2024/3/18
* @jdkversion jdk21
*
* 抽象策略
*/
public interface Pay {
void pay(String type);
}
public abstract class AbstractPay implements Pay {
// 类注册方法
public void register() {
PayContext.registerStrategy(getClass().getSimpleName(), this);
}
}
java
/**
* @author maoyouhua
* @time 2024/3/18
* @jdkversion jdk21
*
* 策略环境
*/
@Component
public class PayContext {
private static final Map<String, Pay> registerMap = new HashMap<>();
// 注册策略
public static void registerStrategy(String payType, Pay strategy) {
registerMap.putIfAbsent(payType, strategy);
}
// 获取策略
public static Pay getStrategy(String payType) {
return registerMap.get(payType);
}
}
java
/**
* @author maoyouhua
* @time 2024/3/18
* @jdkversion jdk21
* 具体策略
* 支付宝支付
*/
@Component
public class Alipay extends AbstractPay {
public Alipay() {
super.register();
}
private static final String payType = "支付宝支付";
@Override
public void pay(String parm) {
System.out.println(parm);
System.out.println("调用" + payType + "方式");
}
}
@Component
public class PostalPay extends AbstractPay {
public PostalPay() {
super.register();
}
private static final String payType = "邮政支付";
@Override
public void pay(String parm) {
System.out.println(parm);
System.out.println("调用" + payType + "方式");
}
}
@Component
public class WeChatPay extends AbstractPay {
public WeChatPay() {
super.register();
}
private static final String payType = "微信支付";
@Override
public void pay(String parm) {
System.out.println(parm);
System.out.println("调用" + payType + "方式");
}
}
java
/**
* @author maoyouhua
* @time 2024/3/18
* @jdkversion jdk21
*/
public interface PayServiceByrebuild {
void payment(String payType, String params);
}
@Service
public class PayServiceImplByrebuild implements PayServiceByrebuild {
@Override
public void payment(String payType, String params) {
Pay pay = PayContext.getStrategy(payType);
pay.pay(params);
}
}
java
/**
* @author maoyouhua
* @time 2024/3/18
* @jdkversion jdk21
*/
@RestController
@RequestMapping("/payment")
public class PayController {
@Autowired
private PayService payService;
@Autowired
private PayServiceByrebuild payServiceByrebuild;
@RequestMapping("/test")
public String testPay(){
return "测试调用支付接口";
}
@RequestMapping("/pay")
public String testPay(String payType, String parm){
payService.payment(payType,parm);
return "调用普通支付接口";
}
@RequestMapping("/paybystrategy")
public String testPayByRebulid(String payType, String parm){
payServiceByrebuild.payment(payType,parm);
return "调用策略模式支付接口";
}
}