项目中常见的几种策略模式实现方式

前言

  本篇文章主要介绍本人在自己项目中和开源项目中策略模式的实现方式

基于spring实现策略模式

  1. 最近在使用nacos-sync同步工具时发现其使用了策略模式,下面主要介绍它是如何使用的

  2. 实现步骤
    2.1 定义接口:SyncService

    public interface SyncService {
    	boolean sync(TaskDO taskDO);
    }
    

    2.2 多个SyncService接口实现类,下面举例一个ZookeeperSyncToNacosServiceImpl

    // @NacosSyncService注解包含@Component
    @NacosSyncService(sourceCluster = ClusterTypeEnum.ZK, destinationCluster = ClusterTypeEnum.NACOS)
    public class ZookeeperSyncToNacosServiceImpl implements SyncService {
    	 @Override
        public boolean sync(TaskDO taskDO) {
        	// 同步代码忽略   
            return true;
        }
    }
    

    2.3 在SyncManagerService类中进行策略分发

    @Service
    public class SyncManagerService implements InitializingBean, ApplicationContextAware {
    	private ConcurrentHashMap syncServiceMap = new ConcurrentHashMap();
    	private ApplicationContext applicationContext;
    	
    	// 通过来源和去向为key在syncServiceMap查看对应SyncService进行同步
    	public boolean sync(TaskDO taskDO) {
            return getSyncService(taskDO.getSourceClusterId(), taskDO.getDestClusterId()).sync(taskDO);
        }
    
    	// 从spring容器中查找带NacosSyncService注解的类并放入syncServiceMap中
    	@Override
        public void afterPropertiesSet() {
            this.applicationContext.getBeansOfType(SyncService.class).forEach((key, value) -> {
                NacosSyncService nacosSyncService = value.getClass().getAnnotation(NacosSyncService.class);
                ClusterTypeEnum sourceCluster = nacosSyncService.sourceCluster();
                ClusterTypeEnum destinationCluster = nacosSyncService.destinationCluster();
                syncServiceMap.put(generateSyncKey(sourceCluster, destinationCluster), value);
            });
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            this.applicationContext = applicationContext;
        }
    
    	public SyncService getSyncService(String sourceClusterId, String destClusterId) {
            ClusterTypeEnum sourceClusterType = this.skyWalkerCacheServices.getClusterType(sourceClusterId);
            ClusterTypeEnum destClusterType = this.skyWalkerCacheServices.getClusterType(destClusterId);
    
            return syncServiceMap.get(generateSyncKey(sourceClusterType, destClusterType));
        }
    }
    

基于Lambda方式实现

  1. 上面实现需要写很多实现类,如果不想写很多实现类可以考虑用lambda方式实现
  2. 下面展示重要策略分发类:AcoChildCompServiceDispatcher
    @Service
    public class AcoChildCompServiceDispatcher {
    
        private Map> handlers = new ConcurrentHashMap<>();
    
        @Resource
        private AcoChildCompService acoChildCompService;
    
    	// 在初始化将策略方法添加到handlers中
        @PostConstruct
        public void init(){
            handlers.put(ComTypeEnum.FRONT.getValue(), acoChildCompService::saveAcoChildInfoByParseWebpackCommon);
            handlers.put(ComTypeEnum.SERVER.getValue(),acoChildCompService::saveAcoChildInfoByParsePom);
        }
    	
    	// 策略分发
        public void dispatcher(ProjectInfo projectInfo, ProCode proCode){
            String comType = proCode.getComType();
            BiConsumer consumer = handlers.get(comType);
            consumer.accept(projectInfo,proCode);
        }
    }
    

基于SPI的插件机制

  1. 上面都是要在项目中增加策略实现类,那能不能加载外面策略实现类呢?最近在看nacos的插件机制,下面把其中重要步骤抽取出来
    1.1 整体项目结构如下
    (1)plugin模块定义插件规则
    (2)自定义插件(例如下图的hello-plugin模块)必须实现HelloPluginService接口,然后META-INF/services下插件接口文件中定义对应的实现类
    (3)在plugin-demo-starter模块中通过SPI加载HelloPluginService接口的实现类
    项目中常见的几种策略模式实现方式_第1张图片

    1.2 将自定义插件hello-plugin的jar包放在项目的plugin目录下,然后通过-Dloader.path指定其插件包的位置
    在这里插入图片描述
    (1)注意:plugin-demo-starter模块的pom文件,layout为ZIP配置很重要 项目中常见的几种策略模式实现方式_第2张图片

  2. 实现步骤
    2.1 定义一个插件模块,定义插件接口(自定义插件必须引入插件包,实现其接口)

    public interface HelloPluginService {
        String helloContent();
    
        String getHelloServiceName();
    }
    

    2.2 自定义插件实现插件接口HelloPluginService,并通过META-INF/services下插件接口文件中定义对应的实现类

    public class TestHelloPluginService implements HelloPluginService {
        public String helloContent() {
            return "Love you";
        }
    
        public String getHelloServiceName() {
            return "test";
        }
    }
    

    项目中常见的几种策略模式实现方式_第3张图片
    2.3 在应用模块通过SPI加载HelloPluginService实现类

    @RestController
    @RequestMapping("/demo")
    public class DemoController {
    
        @RequestMapping("/hello")
        public String hello(String name,String helloServiceName){
            Optional helloPluginService =  HelloPluginManager.getInstance().findHelloServiceSpiImpl(helloServiceName);
            if(helloPluginService.isPresent()){
                String content = helloPluginService.get().helloContent();
                return "hello "+name+", "+content;
            }
            return "hello "+name;
        }
    }
    

你可能感兴趣的:(杂谈,策略模式,java,spring)