策略模式 + Spring 容器
前段时间在做关于流程的需求,因为流程的操作比较多,比如说审核通过、审核拒绝、审核撤销、审核退回等等,每一种操作有自己的处理逻辑,为了便于扩展,想到了策略模式,这里记录一下。
策略模式的使用基本步骤就是定义接口、添加实现类来实现接口、创建工厂类来管理实现类。
在使用工厂的时候遇到一个问题,就是如何将 Bean 注入到工厂中,因为框架使用的是 Spring Boot,所以就要想到在 Bean 中获取容器信息,然后从容器中取出 Bean,因为工厂类本身不是一个 Bean,所以就需要额外的一个类来做前面的 Bean,将这个类作为容器的工具类,具体实现如下。
策略模式
接口
首先是策略模式的接口:
/**
* 审核操作接口
* @author wangzhi
*/
public interface AuditStrategy {
/**
* 操作
* @param auditDto 审核辅助对象
*/
void audit(AuditDto auditDto);
}
这里写的比较简单,至于 AuditDto 就是辅助处理类,根据自己的业务定义就好,我这里方便,就只有一个名字,如下:
/**
* 审核辅助类
* @author wangzhi
*/
@Data
public class AuditDto {
/**
* 审核人姓名
*/
private String name;
}
实现类
简单演示,不写具体的业务
审核通过:
/**
* 审核通过
* @author wangzhi
*/
@Component
public class ApprovalAudit implements AuditStrategy {
@Override
public void audit(AuditDto auditDto) {
System.out.println("ApprovalAudit audit");
}
}
审核拒绝:
/**
* 拒绝操作
* @author wangzhi
*/
@Component
public class RejectAudit implements AuditStrategy {
@Override
public void audit(AuditDto auditDto) {
System.out.println("RejectAudit audit");
}
}
审核退回:
/**
* 退回
* @author wangzhi
*/
@Component
public class ReturnAudit implements AuditStrategy {
@Override
public void audit(AuditDto auditDto) {
System.out.println("ReturnAudit audit");
}
}
工厂类
import com.ioc.springioc.design.impl.ApprovalAudit;
import com.ioc.springioc.design.impl.RejectAudit;
import com.ioc.springioc.design.impl.ReturnAudit;
import com.ioc.springioc.util.ApplicationContextUtils;
import java.util.HashMap;
import java.util.Map;
/**
* 策略模式工厂类
* @author wangzhi
*/
public class AuditStrategyFactory {
private static final Map<String, AuditStrategy> STRATEGIES = new HashMap<>();
static {
// 难度就在于这里如何将 Bean 注入进来
STRATEGIES.put("APPROVAL", (ApprovalAudit) ApplicationContextUtils.getBean(ApprovalAudit.class));
STRATEGIES.put("REJECT", (RejectAudit) ApplicationContextUtils.getBean(RejectAudit.class));
STRATEGIES.put("RETURN", (ReturnAudit) ApplicationContextUtils.getBean(ReturnAudit.class));
}
/**
* 根据操作返回真实的对象
* @param audit 操作
* @return 对象
*/
public static AuditStrategy getAuditStrategy(String audit) {
AuditStrategy auditStrategy = STRATEGIES.get(audit);
if (auditStrategy == null) {
// 可以传入自己项目的自定义异常处理
throw new RuntimeException("请传入有效的操作");
}
return auditStrategy;
}
private AuditStrategyFactory() {}
}
Spring 容器工具类
在 Bean 中获取容器信息有两种方式:
- 第一种就是实现 BeanFactoryAware 或者 ApplicationContextAware 接口
- 使用 @Autowired 注解来注入 BeanFactory 或 ApplicationContext
这里使用了第一种方式,因为要在静态方法中使用
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
/**
* Spring 容器工具类
* @author wangzhi
*/
@Component
public class ApplicationContextUtils implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if(ApplicationContextUtils.applicationContext == null){
ApplicationContextUtils.applicationContext = applicationContext;
}
}
/**
* 根据类型获取 Bean
* @param clazz byType
* @return 类
*/
public static Object getBean(Class<?> clazz) {
return applicationContext.getBean(clazz);
}
}
如上基本就结束了,测试类随便写就好:
@SpringBootTest
class SpringIocApplicationTests {
@Test
void contextLoads() {
}
@Test
void testStrategyAndIoc() {
AuditDto auditDto = new AuditDto();
// 可传入不同的操作获取不同的实例
AuditStrategy approval = AuditStrategyFactory.getAuditStrategy("APPROVAL");
approval.audit(auditDto);
}
}