基于Spring Boot+Vue的博客系统 14——使用策略模式实现评论功能

需求

上一篇文章主要介绍了评论功能的实现,一条评论有一级评论和二级评论两种类型,在CommentService里面我们根据评论的类型的不同进行不同的操作,如下:
基于Spring Boot+Vue的博客系统 14——使用策略模式实现评论功能_第1张图片
这里我们可以使用策略模式实现对此功能的重构。(注意:重构之后的代码在性能上或许还没有原来的代码好,甚至还有一点画蛇添足,这里只用于练习策略模式的使用)

使用策略模式之后

使用策略模式之后的代码如下,业务层代码比之前更简单,而且扩展性更强
基于Spring Boot+Vue的博客系统 14——使用策略模式实现评论功能_第2张图片

处理器上下文

这里的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

你可能感兴趣的:(基于Spring Boot+Vue的博客系统 14——使用策略模式实现评论功能)