再谈策略模式

79 阅读1分钟

定义

  • 是一种行为设计模式, 它能让你定义一系列算法实现, 并将每种实现分别放入独立的类中, 以使算法的对象能够相互替换

类图

实现方式1

  • 目前日常开发中常用的一种方式,快递路由的订阅回调接口为例
@Component
public class RouteNoticeCalculatorFactory implements ApplicationContextAware {

        /**
* 维护 shippingKey 与 具体实现bean 映射关系
*/
private final Map<String, RouteNoticeCalculatorStrategy> routeNoticeCalculatorStrategyMap = new ConcurrentHashMap<>(16);


@Override
public void setApplicationContext(ApplicationContext applicationContext) {

Map<String, RouteNoticeCalculatorStrategy> beans = applicationContext.getBeansOfType(RouteNoticeCalculatorStrategy.class);

for (Entry<String, RouteNoticeCalculatorStrategy> stringRouteNoticeCalculatorStrategyEntry : beans.entrySet()) {
                RouteNoticeCalculatorStrategy routeNoticeCalculatorStrategy = stringRouteNoticeCalculatorStrategyEntry.getValue();
                routeNoticeCalculatorStrategyMap.put(routeNoticeCalculatorStrategy.getShippingKey().name(), routeNoticeCalculatorStrategy);
            }

}

        /**
* 路由回调入口
*
* @param shippingKey  shippingKey
* @param parameterMap 请求参数
* @return 结果
*/
public Object calculate(String shippingKey,Map<String,String[]> parameterMap){
            Assert.hasText(shippingKey,"入参不合法,缺少shippingKey!");

LoggerMessageUtil.info(String.format("%s   parameterMap:%s", shippingKey, JsonUtil.toJsonString(parameterMap)));

RouteNoticeCalculatorStrategy routeNoticeCalculatorStrategy = routeNoticeCalculatorStrategyMap.get(shippingKey);
            Assert.notNull(routeNoticeCalculatorStrategy, ShippingKeyEnum.valueOf(shippingKey).name()+"路由回调接口还未实现!");

            Object response =  routeNoticeCalculatorStrategy.calculate(parameterMap);

LoggerMessageUtil.info(String.format("%s   parameterMap:%s  response:%s", shippingKey, JsonUtil.toJsonString(parameterMap),response.toString()));
            return response;
        }
    }

实现方式2

demo

  • 基于最小插件系统 spring-plugin 实现

  • 项目pom.xml中引入

<dependency>
  <groupId>org.springframework.plugin</groupId>
  <artifactId>spring-plugin-core</artifactId>
  <version>2.0.0.RELEASE</version>
</dependency>

源码分析

  • 从哪里当做源码入口去看?

    • @EnablePluginRegistries 注解
  • Bean是如何注册的?

    • org.springframework.plugin.core.config.PluginRegistriesBeanDefinitionRegistrar

  • 核心接口

    • plugin的容器:org.springframework.plugin.core.PluginRegistry

  • 注意点

    • 可以加上 @Order 注解排序策略的实现
    • 业务实现上注入的名字一定是 接口名 + Registry,除非加了@Qualifier注解
String beanName = annotation == null //
					? StringUtils.uncapitalize(type.getSimpleName() + "Registry") //
					: annotation.value();

一点思考

  • 真正掌握不同设计模式的使用场景,切勿滥用

  • 尝试学会并习惯去看英文文档学习(包括解决一些问题)

  • 看源码,先简后难,先整体后局部,带着问题去看效果更佳

  • 关于分享,费曼学习法

参考