前言
在阅读了一篇微信公众号文章《用设计模式干掉 if-else,太优雅了!》后,考虑到在SpringBoot项目中真实使用时,策略是IoC管理的而不是每次都由工厂创建,所以按自己的思路实现了一版比较简单的方案。
代码
代码清单
TypeEnum.java // 类型枚举类
ReceiptReq.java // 接口请求入参
ReceiptHandleStrategy.java // 接口
DefaultReceiptHandleStrategy.java // 默认接口实现
MT1101ReceiptHandleStrategy.java // MT1101类型对应的接口实现
Mt2101ReceiptHandleStrategy.java // MT2101类型对应的接口实现
ReceiptStrategyTest.java // 测试类
枚举类TypeEnum.java
package cn.cliveyuan.learn.test.strategy;
/**
* @author Clive Yuan
* @date 2023-10-20 16:32
*/
public enum TypeEnum {
MT1101, MT2101, MT4101, MT8104, MT8105, MT9999
}
接口请求入参类ReceiptReq.java
package cn.cliveyuan.learn.test.strategy;
import lombok.Data;
/**
* @author Clive Yuan
* @date 2023-10-20 16:32
*/
@Data
public class ReceiptReq {
private TypeEnum typeEnum;
private String data;
}
接口类ReceiptHandleStrategy.java
package cn.cliveyuan.learn.test.strategy;
/**
* @author Clive Yuan
* @date 2023-10-20 16:33
*/
public interface ReceiptHandleStrategy {
/**
* 获取类型枚举 (每个类型实现类中指定)
*/
TypeEnum getType();
/**
* 处理业务逻辑
*/
void handleReceipt(ReceiptReq receipt);
}
默认接口实现类DefaultReceiptHandleStrategy.java
package cn.cliveyuan.learn.test.strategy;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* @author Clive Yuan
* @date 2023-10-20 16:34
*/
@Component
@Primary // 默认实现
public class DefaultReceiptHandleStrategy implements ReceiptHandleStrategy {
/**
* 从IoC容器中获取所有实现了ReceiptHandleStrategy接口的Bean
*/
@Resource
private List<ReceiptHandleStrategy> receiptHandleStrategyList;
/**
* 定义一个静态Map用于存储类型枚举对应的实现
*/
private static final Map<TypeEnum, ReceiptHandleStrategy> STRATEGY_MAP = new HashMap<>();
/**
* 初始化
* 遍历所有接口实现类,获取其类型并存入Map中
*/
@PostConstruct
public void init() {
for (ReceiptHandleStrategy receiptHandleStrategy : receiptHandleStrategyList) {
// 跳过type为空的实现类,即当前默认实现类DefaultReceiptHandleStrategy
if (Objects.isNull(receiptHandleStrategy.getType())) continue;
STRATEGY_MAP.put(receiptHandleStrategy.getType(), receiptHandleStrategy);
}
}
@Override
public TypeEnum getType() {
// 当前为默认实现,这个类型不必填写
return null;
}
@Override
public void handleReceipt(ReceiptReq receipt) {
// 从Map中获取对应类型的实现类
ReceiptHandleStrategy receiptHandleStrategy = STRATEGY_MAP.get(receipt.getTypeEnum());
// 判断是否为空
if (Objects.isNull(receiptHandleStrategy)) {
throw new RuntimeException("Not support this type:" + receipt.getTypeEnum());
}
// 调用对应接口
receiptHandleStrategy.handleReceipt(receipt);
}
}
MT1101类型对应的接口实现类MT1101ReceiptHandleStrategy.java
package cn.cliveyuan.learn.test.strategy;
import org.springframework.stereotype.Component;
/**
* @author Clive Yuan
* @date 2023-10-20 16:34
*/
@Component
public class MT1101ReceiptHandleStrategy implements ReceiptHandleStrategy {
@Override
public TypeEnum getType() {
// 填写对应的类型枚举
return TypeEnum.MT1101;
}
@Override
public void handleReceipt(ReceiptReq receipt) {
// 处理对应的业务场景
System.out.println("解析报文MT1101:" + receipt.getData());
}
}
MT2101类型对应的接口实现类Mt2101ReceiptHandleStrategy.java
package cn.cliveyuan.learn.test.strategy;
import org.springframework.stereotype.Component;
/**
* @author Clive Yuan
* @date 2023-10-20 16:34
*/
@Component
public class Mt2101ReceiptHandleStrategy implements ReceiptHandleStrategy {
@Override
public TypeEnum getType() {
// 填写对应的类型枚举
return TypeEnum.MT2101;
}
@Override
public void handleReceipt(ReceiptReq receipt) {
// 处理对应的业务场景
System.out.println("解析报文MT2101:" + receipt.getData());
}
}
测试类ReceiptStrategyTest.java
package cn.cliveyuan.learn.test.strategy;
import cn.cliveyuan.learn.test.BaseTest;
import org.junit.Test;
import javax.annotation.Resource;
/**
* @author Clive Yuan
* @date 2023-10-20 16:36
*/
public class ReceiptStrategyTest extends BaseTest {
@Resource
private ReceiptHandleStrategy receiptHandleStrategy;
@Test
public void test_01() {
ReceiptReq receipt = new ReceiptReq();
receipt.setTypeEnum(TypeEnum.MT1101);
receipt.setData("Hi, MT1101");
receiptHandleStrategy.handleReceipt(receipt);
}
@Test
public void test_02() {
ReceiptReq receipt = new ReceiptReq();
receipt.setTypeEnum(TypeEnum.MT2101);
receipt.setData("Hi, MT2101");
receiptHandleStrategy.handleReceipt(receipt);
}
@Test
public void test_03() {
ReceiptReq receipt = new ReceiptReq();
receipt.setTypeEnum(TypeEnum.MT4101);
receipt.setData("Hi, MT4101");
receiptHandleStrategy.handleReceipt(receipt);
}
}
基础测试类BaseTest.java
package cn.cliveyuan.learn.test;
/**
* 基本测试
* @author Clive Yuan
* @date 2023-10-20 16:36
*/
import cn.cliveyuan.learn.Application;
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@SpringBootTest(classes = Application.class)
public class BaseTest {
}
测试结果
test_01: 解析报文MT1101:Hi, MT1101
test_02: 解析报文MT2101:Hi, MT2101
test_03: java.lang.RuntimeException: Not support this type:MT4101
扩展性
如果要新加一个处理类型,只需2步:
- 在类型枚举
TypeEnum.java
中新增枚举值 - 新增一个接口
ReceiptHandleStrategy
的实现,并填写对应的类型枚举
结语
ReceiptHandleStrategy
接口调用时只需要依赖这个接口即可,因为默认实现加了@Primary
注解就会默认调用这个实现处理,并根据类型枚举路由到对应的实现,在实现的类里面就可以方便地依赖其他Bean做业务处理了。
你对这种方式有什么看法呢? 评论区见^_^
@Author: Clive 博客地址:cliveyuan.cn
本文由 Clive 创作,采用 知识共享署名4.0 国际许可协议进行许可
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名
最后编辑时间为:
2023/10/20 17:17