在项目的应用里,有很多功能都是通过前端传过来的key,去判断走哪一个处理类。一开始的时候是一个简单工厂模式的变型,用if..else的判断来做处理的分发,根据参数得到对应的类之后,直接执行了对应的方法。所以严格的说,这是简单工厂模式加策略模式。
个人理解:
(1)简单工厂模式是把创建对象的权利交给了工厂,由工厂根据传入的参数来返回用户需要的对象。然后用户拿到对象再去自己执行方法。
(2)策略模式则是由用户来负责创建对象,然后把对象传给策略类,由策略类来执行对应的方法,返回参数。
例如下面这种代码:
@Component
public class testFactory {
@Resource
private Handle1 handle1;
@Resource
private Handle2 handle2;
...
public ResultDTO getParameter(String key, String value, ContextDTO contextDto, Object response) {
ResultDTO resultDTO = null;
if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) {
resultDTO = ResultDTO.fail("key,value格式非法");
} else if ("key1".equals(key)) {
resultDTO = handle1.generate(contextDto, response);
} else if ("key2".equals(key)) {
resultDTO = handle2.generate(contextDto, response);
}
...
}else {
resultDTO = ResultDTO.fail("key: " + key + "不合法,未找到此上下文值");
}
return resultDTO;
}
}
为了引用端的方便,直接在工厂类里面注入所需要的bean,并且根据传入的参数,选择使用哪一种bean的genearte方法并执行。一开始的服务不多的时候,这样写影响不大。但是后期这种处理类越来越多,代码变得很冗长,并且单纯的if..else的添加逻辑是违背“开闭原则”,对扩展开放,对修改关闭。所以后期想办法对这块做了优化。
1.首先是给每一个handle处理类都加了一个getKey()的方法
(1)接口定义增加方法
public interface HandleService {
String generate(ContextDTO contextDto, Object response);
/**
* 返回handle方法对应的key
* @return
*/
String getKey();
}
(2)每个handle方法增加getKey方法
@Service
public class Handle1 implements HandleService {
private static final Logger log = LoggerFactory.getLogger(Handle1.class);
@Override
public String generate(ContextDTO ContextDto, Object response){
System.out.println("执行generate方法");
}
@Override
public String getGenerateKey(){
return GenerateKeyEnum.KEY1.getGenerateKey();
}
}
(3)key用枚举类或者常量来收口。这样方便维护和理解。
public enum GenerateKeyEnum {
KEY1("key1","key1"),
KEY2("key2","key2");
private String generateKey;
private String generateVal;
GenerateKeyEnum(String generateKey,String generateVal){
this.generateKey = generateKey;
this.generateVal = generateVal;
}
public static GenerateKeyEnum getEnumByName(String generateKey,String generateVal){
for (GenerateKeyEnum generateKeyEnum : GenerateKeyEnum.values()) {
if (generateKeyEnum.getGenerateKey().equals(generateKey) && generateKeyEnum.getGenerateVal().equals(generateVal)) {
return generateKeyEnum;
}
}
return null;
}
public String getGenerateVal() {
return generateVal;
}
public String getGenerateKey() {
return generateKey;
}
public void setGenerateKey(String generateKey) {
this.generateKey = generateKey;
}
public void setGenerateVal(String generateVal) {
this.generateVal = generateVal;
}
}
2.然后是对工厂类的修改:
@Component
public class StrategyFactory {
private static final Map<String, HandleService> handleServiceMap = new HashMap<>();
@Resource
private Set< HandleService > handleServiceSet;
@PostConstruct
private void init() {
if (handleServiceSet != null) {
handleServiceSet.forEach(handleService ->
handleServiceMap.put(handleService.getKey(), handleService)
);
}
}
public HandleService getHandleService(String key) {
return handleServiceMap.get(key);
}
public ResultDTO getParameter(String key, String value, ContextDTO contextDto, Object response) {
if (StringUtils.isBlank(key) || StringUtils.isBlank(value)) {
return ServiceResultDTO.fail("key,value格式非法");
} else {
HandleService handleService = getHandleService(key);
if (handleService == null) {
return ResultDTO.fail("key: " + key + "不合法,未找到bean");
}
return handleService.generate(contextDto, response);
}
}
}
在这里,直接用注解的方式把所有的service全部注入到set集合中,然后将set中的内容放到map里面,方便获取。因为类初始化后,开始注入bean,而注解的顺序@Autowired > @PostConstruct > @PreDestroy,从而可以保证map中有值。
1.每当需要加一个处理类的时候,只需要新增处理类,并且在枚举类中维护一个key即可,不要修改工厂类,代码变的更加简洁,易于维护。
2.灵活的组合各种设计模式和运用注解,可以让项目的代码更清晰。