上一篇文章主要介绍了评论功能的实现,一条评论有一级评论和二级评论两种类型,在CommentService
里面我们根据评论的类型的不同进行不同的操作,如下:
这里我们可以使用策略模式实现对此功能的重构。(注意:重构之后的代码在性能上或许还没有原来的代码好,甚至还有一点画蛇添足,这里只用于练习策略模式的使用)
使用策略模式之后的代码如下,业务层代码比之前更简单,而且扩展性更强
这里的handContext
为处理器上下文,可以获取根据评论类型获取不同的处理器
package com.qianyucc.blog.handler;
import com.qianyucc.blog.model.enums.*;
import com.qianyucc.blog.utils.*;
import java.util.*;
/**
* @author lijing
* @date 2019-10-13 15:54
* @description 处理器上下文,用来保存不同的业务处理器
*/
public class HandlerContext {
private Map<CommentTypeEnums, Class> handlerMap;
public HandlerContext(Map<CommentTypeEnums, Class> handlerMap) {
this.handlerMap = handlerMap;
}
public AbstractHandler getInstance(CommentTypeEnums type) {
Class<AbstractHandler> clazz = handlerMap.get(type);
return SpringUtil.getBean(clazz);
}
}
AbstractHandler
为处理器的抽象类,定义了处理器的规范
package com.qianyucc.blog.handler;
import com.qianyucc.blog.model.dto.*;
/**
* @author lijing
* @date 2019-10-13 15:55
* @description 策略模式:抽象处理器
*/
public abstract class AbstractHandler {
abstract public void handle(CommentDTO commentDTO);
}
SpringUtil
为自定义工具类,可以获取Spring中执行上下文,我们可以根据执行上下文从拿到指定的bean
package com.qianyucc.blog.utils;
import org.springframework.beans.*;
import org.springframework.context.*;
import org.springframework.stereotype.*;
/**
* @author lijing
* @date 2019-10-13 15:56
* @description Spring上下文工具类
*/
@Component
public class SpringUtil implements ApplicationContextAware {
private static ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
if (SpringUtil.applicationContext == null) {
SpringUtil.applicationContext = applicationContext;
}
}
//获取applicationContext
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
//通过name获取 Bean.
public static Object getBean(String name) {
return getApplicationContext().getBean(name);
}
//通过class获取Bean.
public static <T> T getBean(Class<T> clazz) {
return getApplicationContext().getBean(clazz);
}
//通过name,以及Clazz返回指定的Bean
public static <T> T getBean(String name, Class<T> clazz) {
return getApplicationContext().getBean(name, clazz);
}
}
CommentTypeEnums
为自定义枚举类型,用来表示评论类型
package com.qianyucc.blog.model.enums;
import com.qianyucc.blog.exception.*;
/**
* @author lijing
* @date 2019-10-13 15:59
* @description 表示评论类型
*/
public enum CommentTypeEnums {
FIRST_LEVEL_COMMENT(1),
SECOND_LEVEL_COMMENT(2);
private Integer type;
CommentTypeEnums(Integer type) {
this.type = type;
}
public static CommentTypeEnums getType(Integer type) {
if (1 == type) {
return FIRST_LEVEL_COMMENT;
} else if (2 == type) {
return SECOND_LEVEL_COMMENT;
} else {
throw new UnknowCommentTypeException();
}
}
}
UnknowCommentTypeException
为自定义异常,当评论类型为非法类型的时候触发
package com.qianyucc.blog.exception;
/**
* @author lijing
* @date 2019-10-13 16:15
* @description 未知评论类型异常
*/
public class UnknowCommentTypeException extends RuntimeException {
public UnknowCommentTypeException() {
super("评论类型错误!");
}
public UnknowCommentTypeException(String message) {
super(message);
}
}
自定义注解CommentType
来表示不同类型的处理器对应的评论类型
package com.qianyucc.blog.model.annotations;
import com.qianyucc.blog.model.enums.*;
import java.lang.annotation.*;
/**
* @author lijing
* @date 2019-10-13 15:58
* @description 自定义注解,用于表示评论类型
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface CommentType {
CommentTypeEnums value();
}
分别定义处理一级评论和二级评论的处理器
package com.qianyucc.blog.handler.comment;
import com.qianyucc.blog.handler.*;
import com.qianyucc.blog.model.annotations.*;
import com.qianyucc.blog.model.dto.*;
import com.qianyucc.blog.model.entity.*;
import com.qianyucc.blog.model.enums.*;
import com.qianyucc.blog.repository.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
import java.util.*;
/**
* @author lijing
* @date 2019-10-13 16:20
* @description 策略模式:一级评论处理器
*/
@Component
@CommentType(CommentTypeEnums.FIRST_LEVEL_COMMENT)
public class FirstLevelCommentHandler extends AbstractHandler {
@Autowired
private ArticleRepository articleRepository;
@Override
public void handle(CommentDTO commentDTO) {
Optional<ArticleDO> byId = articleRepository.findById(commentDTO.getParentId());
byId.ifPresent(articleDO -> {
articleDO.setComments(articleDO.getComments() + 1);
articleRepository.save(articleDO);
});
}
}
package com.qianyucc.blog.handler.comment;
import com.qianyucc.blog.handler.*;
import com.qianyucc.blog.model.annotations.*;
import com.qianyucc.blog.model.dto.*;
import com.qianyucc.blog.model.entity.*;
import com.qianyucc.blog.model.enums.*;
import com.qianyucc.blog.repository.*;
import org.springframework.beans.factory.annotation.*;
import org.springframework.stereotype.*;
import java.util.*;
/**
* @author lijing
* @date 2019-10-13 16:22
* @description 策略模式:处理二级评论
*/
@Component
@CommentType(CommentTypeEnums.SECOND_LEVEL_COMMENT)
public class SecondLevelCommentHandler extends AbstractHandler {
@Autowired
private CommentRepository commentRepository;
@Override
public void handle(CommentDTO commentDTO) {
Optional<CommentDO> byId = commentRepository.findById(commentDTO.getParentId());
byId.ifPresent(commentDO -> {
commentDO.setComments(commentDO.getComments() + 1);
commentRepository.save(commentDO);
});
}
}
最后我们把handlerContext
注入Spring的容器里面
package com.qianyucc.blog.global;
import cn.hutool.core.lang.*;
import com.qianyucc.blog.handler.*;
import com.qianyucc.blog.model.annotations.*;
import com.qianyucc.blog.model.enums.*;
import org.springframework.beans.*;
import org.springframework.beans.factory.config.*;
import org.springframework.stereotype.*;
import java.util.*;
/**
* @author lijing
* @date 2019-10-13 16:05
* @description BeanFactoryPostProcessor是初始化bean时对外暴露的入口
*/
@Component
public class HandlerProcessor implements BeanFactoryPostProcessor {
private static final String HANDLER_PACKAGE = "com.qianyucc.blog.handler.comment";
/**
* 1. 扫描@CommentType注解
* 2. 初始化HandlerContext,将其注入到Spring容器
*
* @param configurableListableBeanFactory
* @throws BeansException
*/
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
HashMap<CommentTypeEnums, Class> handlerMap = new HashMap<>();
ClassScaner.scanPackage(HANDLER_PACKAGE).forEach(clazz -> {
// 获取注解中类型值
CommentTypeEnums value = clazz.getAnnotation(CommentType.class).value();
// 将注解中类型值作为key,对应类作为value,保存在Map中
handlerMap.put(value, clazz);
});
// 初始化HandlerContext,将其注册到Spring容器中
HandlerContext handlerContext = new HandlerContext(handlerMap);
configurableListableBeanFactory.registerSingleton(HandlerContext.class.getName(), handlerContext);
}
}
参考文章:Spring Boot中如何干掉if else