最优美的设计模式-策略模式

设计模式

Posted by TBKK on October 15, 2019

看下面一段代码.

    if (type == 3000) {
        ...
    } else if (type == 3001){
        ...
    } else if (type == 3002){
        ...
    } else {
        ...
    }

这种代码有什么问题吗啊?

  1. 代码看上就很low,比这个高级点的就是switch case了
  2. 如果要增加一个type怎么办?
    • 增加一个if分支
    • 增加一个相应分支的处理方式
  3. 分支代码和处理代码分散在不同区域,维护困难。

比较优雅的代码应该如下:


@UnitType(3000)
public class ExecProcessUnit extends ExecBaseProcessUnit {
    @Override
    protected Object exec(ProcessContext ctx) {
        XXXXXXXX
    }
}

增加一个注解即可优雅的完成。

怎样做到这种方式的呢?

  1. 首先需要一个@UnitType注解:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface UnitType {
    int value() default 0;
}

  1. 需要一个能解析这些注解的类,并且可以开机扫描
@Slf4j
@Component
@Lazy(false)
public class ProcessUnitManager {

    private static final  String PROC_UNIT_PACKAGE ="com.tbkk.xxxx.procunit.impl";

    private static Map<int, ExecBaseProcessUnit> unitMap = new ConcurrentHashMap<>();

    /**
     *
     * scan 处理单元类型和处理单元组件类型
     *
     **/
    @PostConstruct
    private void initScanProcUnit() {
        Set<Class<?>> classes = ClassScanerUtils.scan(PROC_UNIT_PACKAGE, UnitType.class, Component.class);
        for(Class clazz  : classes) {
            UnitType []   unitTypes  = (UnitType []) clazz.getAnnotationsByType(UnitType.class);
            Arrays.stream(unitTypes).forEach( unitType->
                    {
                        unitMap.put(unitType.value(), (ExecBaseProcessUnit)springBeanUtils.getBean(clazz));
                    }
            );
        }
    }
}

  1. 需要一个能定位到这些处理类的动作,指定类进行处理,如下: ``` java

ProcessUnitManager.getUnitMap().get(type).exec(ctx);

```

  1. 以后如果有额外的type出现,在相应的包下面增加处理单元即可。

策略模式和SPI的区别

如果从代码接入的级别来看,策略模式还是在原有项目中进行代码修改,只不过它不会修改原有类中的代码,而是新建了一个类。而 SPI 机制则是不会修改原有项目中的代码,其会新建一个项目,最终以 Jar 包引入的方式代码。

从这一点来看,无论策略模式还是 SPI 机制,他们都是将修改与原来的代码隔离开来,从而避免新增代码对原有代码的影响。但策略模式是类层次上的隔离,而 SPI 机制则是项目框架级别的隔离。

从应用领域来说,策略模式更多应用在业务领域,即业务代码书写以及业务代码重构。而 SPI 机制更多则是用于框架的设计领域,通过 SPI 机制提供的灵活性,让框架拥有良好的插件特性,便于扩展。

附 :想了解SPI的可以看我的另外一篇文章【深入理解SPI】