策略模式+工厂模式代替if else 循环

1.为什么要使用策略模式+工厂类实现
   虽说这种模式看起来十分优雅,但是不可否认多写了接口,工厂类,以及N多个实现类具体类造成编码等成本,但是就ielse if...业务代码很长(原谅我没文化啊)代码的维护将变得十分困难,光这一点就值得使用模式优化了

 

2.讨论
   个人觉得使用工厂类+反射注入实际解决问题的实现类特好,但是我没有完美解决该问题.如下代码所示

​
    public static StrategyService getStrategyImpl(String strategyType) throws Exception {
        /*
         * getStrategyImpl():  是通过反射+枚举类(valueOf())获取类全路径
         * StrategyService: 为我抽取的接口
         * StatusEnum: 枚举类
         *
         * */
        String className = StatusEnum.valueOf(strategyType).getClassName();
        return (StrategyService) Class.forName(className).newInstance();
    }

​


该工厂类使用反射newInstance(),方法在本质上还是new了,但是 new 后就不归属于 spring 容器管理了,这就造成了我在实现类中在使用其他serviceImpl实现类或者dao调用数据保存出现注入的值本身是null.也不是没有解决的方法这不是说本质上我没有获取的spring上管理的bean呗,所以跳过new的实例,直接获取spring容器中的Bean是否可行?
先创建springUtil方法
 

@Component
public class BeanUtils implements ApplicationContextAware {

    protected static ApplicationContext applicationContext;

    @Override
    public void setApplicationContext(ApplicationContext arg0) throws BeansException {
        if (applicationContext == null) {
            applicationContext = arg0;
        }

    }

    public static Object getBean(String name) {
        //name表示其他要注入的注解name名
        return applicationContext.getBean(name);
    }

    /**
     * 拿到ApplicationContext对象实例后就可以手动获取Bean的注入实例对象
     */
    public static <T> T getBean(Class<T> clazz) {
        return applicationContext.getBean(clazz);
    }
}

再然后在实现类中手动获取bean如下,BeanUtils.getBean(TestApi.class)方法获取实现类bean在执行testApi的新增方法.这种方法虽说实现了要求但是每次调用方法都会调用getBean()方法去获取对象比较耗费资源.

@Slf4j
@Service
public class LoopCoordinateMethodImpl extends LoopMethodAbstract {

    @Override
    public <T> int runAppointed(List<T> lists, String channelName) {
        List<User> list = (User) lists;
        TestApi testApi = BeanUtils.getBean(TestApi.class);
        return testApi.updateBatch(list);
    }

}

3.实现
  再说说另一种方法如何实现,上述核心问题还是工厂类提供的接口实现类是new的而不是注入的呗.
 3.1 抽取接口
 

public interface ILoopMethodService {
    <T> int runAppointed(List<T> list);
}

3.2  实现类

@Service
@Slf4j
public class LoopMethodImpl implements ILoopMethodService {

    @Autowired
    private TestApi testApi;

    @Override
    public <T> int runAppointed(List<T> lists) {
        System.out.println("本身的方法逻辑执行了...");
        System.out.println("lists = " + lists.toString());
        testApi.test01();
        return 0;
    }
}

3.3 另一个不实现该功能接口的实现类(验证)

@Slf4j
@Service
public class TestApi {

    public void test01(){
        System.out.println("调用的方法执行了...");
    }
}

3.4 工厂类

@Component
@Slf4j
public class LoopTypeFactory {

    @Autowired
    private LoopMethodImpl loopCoordinateMethod;

    public ILoopMethodService getLoopMethodImpl(String channelName) {
        Map<String, ILoopMethodService> map = new HashMap<>(16);
        map.put(LoopMethodEnum.COORDINATE_LOOP.channelName, loopCoordinateMethod);
        ILoopMethodService iLoopMethodService = map.get(channelName);
        if (iLoopMethodService == null){
            log.error("抛出异常");
        }
        return iLoopMethodService;
    }
}

3.5 一个简单的枚举类

public enum LoopMethodEnum {

    /*
     *
     * */
    CUST_LOOP("TEST"),
    /*
     * 兜底默认未知方法
     * */
    UNKNOWN("DEFINE"),

    /*
     *  测试的方法
     * */
    COORDINATE_LOOP("RUN");

    public String channelName;//处理方法代号

    LoopMethodEnum(String channelName) {
        this.channelName = channelName;
    }

}

3.6 测试Controller
 

@RestController
@Slf4j
public class TestController {

    @Autowired
    private LoopTypeFactory loopTypeFactory;

    @PostMapping("/test02")
    public void test66(@RequestBody String parameters) {
        List<Object> list = new ArrayList<>();
        list.add("12121");
        list.add("12122");
        list.add("12123");
        list.add("12124");
        ILoopMethodService coordinate = loopTypeFactory.getLoopMethodImpl(LoopMethodEnum.COORDINATE_LOOP.channelName);
        coordinate.runAppointed(list);
    }
}

测试结果如下
策略模式+工厂模式代替if else 循环 

使用该种方法需要在新增实体类的时候需要修改工厂类添加实体类,所以有没有知道如果使用反射来封装但是可以在后续仍然可以使用注入类的方法,如果知道告知下吧,感谢了

上一篇:Spring 循环依赖


下一篇:Spring5源码 - 07 Spring Bean 生命周期流程 源码解读02