策略模式+简单工厂+注解消除 if-else/switch-case
在很多时候,我们代码中会有很多分支,而且分支下面的代码又有一些复杂的逻辑,相信很多人都喜欢用 if-else/switch-case 去实现。做的不好的会直接把实现的代码放在 if-else/switch-case 的分支之下:
switch ( type ) {case case1:......break;case case2:......break;case case3:......breakdefault:return null;}
这样的代码不仅冗长,读起来也非常困难。做的好一点的会把这些逻辑封装成函数然后在分支中调用:
switch ( type ) {case case1:return case1Func();case case2:return case2Func();case case3:return case3Func();default:return null;}
即使这样也是面向过程思维的写法,毫无设计模式可言。不仅违背开闭原则,而且随着 switch-case 分支的增多,该段代码只会越来越冗长。其实这种代码已经有成熟的模式去消除诸多的 if-else/switch-case 分支,即使用 注解+策略模式+简单工厂的方式** **消除 if-else/switch-case 。
1. 定义一个枚举类
public enum TagEvent {/*** 文件*/TAG_FILE(1),/*** paper*/TAG_PAPER(2),/*** 课件*/TAG_COURSEWARE(3),/*** book*/TAG_BOOK(4),/*** 个人book模板*/TAG_BOOKTEMPLATE(5),/*** 游戏*/TAG_GAME(6),/*** 物理实验*/TAG_PHYSICALEXPERIMENT(7);private Integer tag;TagEvent(Integer tag) {this.tag = tag;}public Integer getTag() {return tag;}public void setTag(final Integer tag) {this.tag = tag;}public static TagEvent getEvent(Integer tag) {for (TagEvent value : TagEvent.values()) {if (value.getTag().equals(tag)) {return value;}}return null;}}
2. 自定义 TagEventAnnotation 注解
/*** @description: 自定义文档标签注解* @author: zcq* @date: 2020/6/8 2:15 下午*/@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface TagEventAnnotation {TagEvent value();}
3. 自定义 TagEventProcess 接口
/*** @description: 文档标签 事件接口* @author: zcq* @date: 2020/6/9 2:17 下午*/public interface TagEventProcess {/*** @description: 获取文档 url* @author: zcq* @date: 2020/6/9 2:20 下午*/String getDocumentUrl(TagEventDto document) throws RestClientException;/*** @description: 获取分享 url* @author: zcq* @date: 2020/6/9 2:53 下午*/String publicShare(TagEventDto eventDto) throws RestClientException;/*** @description: 修改名称* @author: zcq* @date: 2020/6/9 3:51 下午*/Result modifyName(TagEventDto eventDto) throws ServiceException;/*** @description: 文档复制* @author: zcq* @date: 2020/6/9 4:20 下午*/void copyDocument(TagEventDto eventDto) throws ServiceException;}
4. 接口实现类
每一个标签类型一个实现类,实现 TagEventProcess 接口,比如:
/**
* @description: book 标签 事件处理类
* @author: zcq
* @date: 2020/6/9 2:01 下午
*/
@Slf4j
@Component
@TagEventAnnotation(TagEvent.TAG_BOOK)
public class TagBookProcess implements TagEventProcess {
@Autowired
private FilePropResource filePropResource;
@Autowired
private BookRestClient bookRestClient;
/**
* @description: 获取 book url
* @author: zcq
* @date: 2020/6/9 2:21 下午
*/
@Override
public String getDocumentUrl(TagEventDto eventDto) throws RestClientException {
String url = eventDto.getFileRestClient().getBookIndexUrl(eventDto.getDocument().getId());
return DocumentPermission.canEdit(eventDto.getPermission()) ? url : url + "&isBrower=1";
}
/**
* @param eventDto
* @description: 获取分享 url
* @author: zcq
* @date: 2020/6/9 2:53 下午
*/
@Override
public String publicShare(TagEventDto eventDto) throws RestClientException {
return null;
}
/**
* @param eventDto
* @description: 修改名称
* @author: zcq
* @date: 2020/6/9 3:51 下午
*/
@Override
public Result modifyName(TagEventDto eventDto) throws ServiceException {
eventDto.getParams().put("id", eventDto.getDocumentDto().getId());
eventDto.getParams().put("title", eventDto.getDocumentDto().getName());
return renameBook(eventDto.getParams());
}
/**
* @param eventDto
* @description: 文档复制
* @author: zcq
* @date: 2020/6/9 4:20 下午
*/
@Override
public void copyDocument(TagEventDto eventDto) throws ServiceException {
eventDto.getParams().put("id", eventDto.getDocumentDto().getId());
eventDto.setResult(copyBook(eventDto.getParams()));
Map<String, String> resultMap = (Map) eventDto.getResult().getData();
eventDto.getDocument().setId(resultMap.get("id"));
eventDto.getDocument().setName(resultMap.get("title"));
}
private Result renameBook(Map params) throws ServiceException {
try {
ValidParameterUtils.validParamNotNull(
params.get("id"),
params.get("title")
);
String token = ValidParameterUtils.getRestParamString(params, filePropResource.getFileRestToken());
params.put("token", token);
ParamsDto paramsDto = new ParamsDto();
Map paramsDtoMap = BeanUtils.bean2Map(paramsDto);
params.putAll(paramsDtoMap);
Result result = bookRestClient.renameBook(params);
return result;
} catch (RestClientException e) {
String errorMessage = "重命名book失败!";
log.error("调用file rest接口 重命名book失败!", e);
throw new ServiceException(errorMessage, e);
}
}
private Result copyBook(Map params) throws ServiceException {
try {
ValidParameterUtils.validParamNotNull(
params.get("id")
);
String token = ValidParameterUtils.getRestParamString(params, filePropResource.getFileRestToken());
params.put("token", token);
ParamsDto paramsDto = new ParamsDto();
Map paramsDtoMap = BeanUtils.bean2Map(paramsDto);
params.putAll(paramsDtoMap);
Result result = bookRestClient.copyBook(params);
return result;
} catch (RestClientException e) {
String errorMessage = "复制book失败!";
log.error("调用file rest接口 复制book失败!", e);
throw new ServiceException(errorMessage, e);
}
}
}
5. 参数封装DTO
/**
* @description: 标签事件请求参数封装
* @author: zcq
* @date: 2020/6/9 3:36 下午
*/
@Data
@Builder
public class TagEventDto {
private Document document;
private FileRestClient fileRestClient;
private Integer permission;
private UserVo userVo;
private String id;
private String url;
private Map<String, Object> params;
private DocumentDto documentDto;
private Result result;
private FileDto fileDto;
}
6. SpringContextUtil 工具类
/**
* @description: 从 Spring context 获取 bean 的工具类
* @author: zcq
* @date: 2020/6/9 1:58 下午
*/
@Component
public class SpringContextUtil implements ApplicationContextAware {
private ApplicationContext context;
public ApplicationContext getContext() {
return context;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.context = applicationContext;
}
}
7. 事件工厂类
/**
* @description: 文档标签事件工厂类
* @author: zcq
* @date: 2020/6/9 1:57 下午
*/
@Component
public class EventProcessFactory {
@Resource
SpringContextUtil springContextUtil;
private static Map<TagEvent, TagEventProcess> eventProcessMap = Maps.newConcurrentMap();
@PostConstruct
public void init() {
Map<String, Object> beanMap = springContextUtil.getContext().getBeansWithAnnotation(TagEventAnnotation.class);
for (Object eventProcess : beanMap.values()) {
TagEventAnnotation annotation = eventProcess.getClass().getAnnotation(TagEventAnnotation.class);
eventProcessMap.put(annotation.value(), (TagEventProcess) eventProcess);
}
}
public static TagEventProcess createEventProcess(TagEvent event) {
return eventProcessMap.get(event);
}
}
8. 调用
之前调用方式:
改造之后:
String url;
// 根据文档的标签类型获取对应分享的 url
TagEventProcess eventProcess = EventProcessFactory.createEventProcess(TagEvent.getEveny(document.getTag()));
if (eventProcess != null) {
TagEventDto eventDto = TagEventDto.builder()
.document(document).id(id).build();
url = eventProcess.publicShare(eventDto);
} else {
throw new Exception("此类型的文件不能分享");
}
