策略模式 + 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);
    }
}
posted @ 2023-03-28 15:21  庄子游世  阅读(88)  评论(0编辑  收藏  举报