策略模式+springboot动态调用多个实现类

相关代码

策略类:

public AssetComplexService getService(Integer type) {
        if(type == null){
            log.error("获取对应实现类失败");
        }
        strategyMap.put(1,assetReceiveService);
        strategyMap.put(2,assetBorrowService);
        strategyMap.put(3,assetReturnService);
        strategyMap.put(4,assetSendbackService);
        return strategyMap.get(type);
    }

实现类1:

@Service("assetReceiveService")
public class AssetReceiveServiceImpl extends ServiceImpl<AssetComplexDao, AssetComplexDO> implements AssetComplexService{....}

实现类2:

@Service("assetBorrowService")
public class AssetBorrowServiceImpl extends ServiceImpl<AssetComplexDao, AssetComplexDO> implements AssetComplexService{....}

实现类3:

@Service("assetReturnService")
public class AssetReturnServiceImpl extends ServiceImpl<AssetComplexDao, AssetComplexDO> implements AssetComplexService{....}

实现类4:

@Service("assetSendbackService")
public class AssetSendbackServiceImpl extends ServiceImpl<AssetComplexDao, AssetComplexDO> implements AssetComplexService{....}

controller类:

public class AssetComplexController {
    
        @Autowired
        AssetService assetService;
        @Autowired
        Factory factory;
    
    @ApiOperation("分页列表")
    @PostMapping("/list")
    public Result<IPage<AssetComplexDO>> list(@RequestBody SearchCommonDTO<?> params, int type){
        Result<IPage<AssetComplexDO>> result = new Result<>();
        AssetComplexService assetComplexService = factory.getService(type);
        result.setResult(assetComplexService.queryPage(params,type));
        return result;
    }

问题:

策略模式自动注入的map:
Map<String,UserService> map;
这里的String怎么优化?
1、用枚举的话,每次新增一个需求还得再更新一些这个枚举类?那就跟一个个put进去一样。
2、每个策略类(实现类)里写一个getUserType方法,但是也得先判断类型才能进入这个策略类(实现类)呀。

想要实现的效果:

新的相同的需求出现的时候,不需要修改我的原有代码(所有),只需新增一个实现类并重写那些方法就行;
传入的type参数为int,而不是String。
万分感谢!

参考springmvc的参数解析器,你的AssetComplexService 加一个boolean support方法,入参就是int type,
这样只要你编码规范,一个type对应一个实现类,这就不需要改任何代码了

img

可以用枚举实现这种策略模式。

新增策略的时候,只需要新增一个实现类,标识 @Service 注解。再添加一个枚举实例就行。

闲着没事儿,我给你写了一个,你可以参考参考

import java.util.HashMap;
import java.util.Map;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;

// 任务执行接口
interface TypeService {
    Object execute();
} 

// 各个实现
@Component
class Type1Service implements TypeService {
    @Override
    public Object execute() {
        return "我是Type1";
    }
}

@Component
class Type2Service implements TypeService {
    @Override
    public Object execute() {
        return "我是Type2";
    }
}

@Component
class Type3Service implements TypeService {
    @Override
    public Object execute() {
        return "我是Type3";
    }
}

@Component
class Type4Service implements TypeService {
    @Override
    public Object execute() {
        return "我是Type4";
    }
}

// 策略枚举
enum Type {
    Type1(1, Type1Service.class),
    Type2(2, Type2Service.class),
    Type3(3, Type3Service.class),
    Type4(4, Type4Service.class),
    ;
    
    private Integer value;
    private Class<? extends TypeService> handler;
    
    private static Map<Integer, Type> enums = new HashMap<>();
    
    static {
        for (Type type : Type.values()) {
            if (enums.containsKey(type.value)) {
                throw new IllegalArgumentException("重复的value值:" + type.value);
            }
            enums.put(type.value, type);
        }
    }
    
    Type(Integer value, Class<? extends TypeService> handler){
        this.value = value;
        this.handler = handler;
    }
    
    public TypeService getService (ApplicationContext applicationContext) {
        return applicationContext.getBean(this.handler);
    }
    
    public static Type get(Integer value) {
        return enums.get(value);
    }
}

@RestController
@RequestMapping("/test")
public class TestController {
    
    @Autowired
    private ApplicationContext applicationContext;
    
    @GetMapping(produces = "text/plain; charset=utf-8")
    public Object test(@RequestParam("type") Integer val) {
        Type type = Type.get(val);
        
        if (type == null) {
            return "策略不存在:" + val;
        }
        
        TypeService service = type.getService(applicationContext);
        if (service == null) {
            return "策略没有实现:" + val;
        }
        
        return service.execute().toString();
    }
}

  @Autowired
        AssetService assetService;

直接改成


  @Autowired
        Map<String,AssetService > map;

然后调用就直接map.get(type) 就行了,不需要你的这个Factory ;

注意这样写你原来的
 @Service("assetReceiveService")
public class AssetReceiveServiceImpl
就得改成:
@Service("1")  // 这个bean的名称自己定义,和map的key对上就行
public class AssetReceiveServiceImpl;


在2楼的基础上修改一下

@RestController
@RequestMapping("/test")
public class testController {
    @Autowired
    private ApplicationContext applicationContext;

    @GetMapping(produces = "text/plain; charset=utf-8")
    public Object test(@RequestParam("type") String beanName) {

        if (beanName== null) {
            return "策略不存在:" + beanName;
        }
        TypeService service =(TypeService) applicationContext.getBean(beanName);
        if (service == null) {
            return "策略没有实现:" + beanName;
        }

        return service.execute().toString();
    }

}

@Service
public class Type1Service implements TypeService {
    @Override
    public Object execute() {
        return "我是Type1";
    }
}

使用beanName 作为入参就行了 不过测试的时候要注意首字母小写spring 内部好像在注册bean的时候做了处理首字母会变为小写

最近在写设计模式相关的论文,嗯
也有这种想法,我的做法是将map的映射关系交给外部配置文件或者是静态代码。
在新写一个类的时候使反射先加载它,并把它放在容器中。
这样做是不管想减少还是增加都可以。