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

废弃说明:
这个专栏的文章本意是记录笔者第一次搭建博客的过程,文章里里有很多地方的写法都不太恰当,现在已经废弃,关于SpringBoot + Vue 博客系列,笔者重新写了这个系列的文章,不敢说写的好,但是至少思路更加清晰,还在看SpringBoot + Vue 博客系列文章的朋友可以移步:https://blog.csdn.net/li3455277925/category_10341110.html,文章中有错误的地方或者大家有什么意见或建议都可以评论或者私信交流。

需求

上一篇文章主要介绍了评论功能的实现,一条评论有一级评论和二级评论两种类型,在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

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值