专栏首页一枝花算不算浪漫【一起学设计模式】访问者模式实战:权限管理树删除节点操作

【一起学设计模式】访问者模式实战:权限管理树删除节点操作

前言

申明: 本文章首发自本人博客:https://www.cnblogs.com/wang-meng 和公众号:壹枝花算不算浪漫 如若转载请标明来源

之前在我的博客(一枝花算不算浪漫)中已经更新过两篇设计模式相关的内容

上面内容都是基于真实业务场景精简后的设计(工作中真实场景使用到的)。

之前为了学习设计模式,看过网上很多相关博客讲解,大都是画下UML类图,举例几个毫不相干的demo,看了几遍仍然是云里雾里。

学习设计模式只有在真正的业务场景去使用才会更好的理解其精髓。这里举例自己工作中电商的业务场景,然后配合一些业务功能的实现,来学会设计模式,使自己的代码更优雅。

业务背景

权限功能模块-权限树-删除树上的某个权限

  1. 要求判断该权限节点及其子节点是否有用户、角色关联,如若有关联则不允许删除
  2. 要求删除该权限节点及其子节点所有数据

常规操作

先说下大多数人为了实现需求都会做的常规操作,这里举例说明,权限A,其子节点B、C

  1. 查找权限A是否被用户、角色关联过
  2. 查找全新啊A下面所有子节点B、C
  3. 查找权限B、C是否被其他用户、角色关联过
  4. 删除A、B、C

这里如果有个流程图效果会更佳,但是相信大家看到文字也能明白其中的运转流程。

这里只是简单地列了下操作的步骤,其实大家可能会做的更好,比如查询、删除 都可以批量去做处理,这里就不再讨论了。

通过上面的流程,我们知道一个方法就可以搞定这几个步骤,只是该方法包含了查询、删除等等逻辑操作,看起来并不精简。

访问者模式实现

  1. 实现类图
  1. 代码实现 这里使用访问者模式 分开一个检查relatePriorityNode的visitor,还有一个removeNode的visitor,如果以后扩展其他操作方式直接增加新的visitor即可。

PriorityNode:

/**
 * 权限树节点
 * @author wangmeng
 *
 */
@Data
public class PriorityNode {

    /**
     * id
     */
    private Long id;
    /**
     * 权限编号
     */
    private String code;
    /**
     * 权限URL
     */
    private String url;
    /**
     * 权限备注
     */
    private String priorityComment;
    /**
     * 权限类型
     */
    private Integer priorityType;
    /**
     * 父权限id
     */
    private Long parentId;
    /**
     * 权限的创建时间
     */
    private Date gmtCreate;
    /**
     * 权限的修改时间
     */
    private Date gmtModified;
    /**
     * 子权限节点
     */
    private List<PriorityNode> children = new ArrayList<PriorityNode>();
    
    /**
     * 接收一个权限树访问者
     * @param visitor 权限树访问者
     */
    public void accept(PriorityNodeVisitor visitor) {
        visitor.visit(this);  
    }
}

PriorityNodeVisitor:

/**
 * 权限树节点的访问者接口
 *
 * @author wangmeng
 * @blog https://www.cnblogs.com/wang-meng/
 * @create 2019-12-01 10:12
 **/
public interface PriorityNodeVisitor {

    /**
     * 访问权限树节点
     *
     * @param node 权限树节点
     */
    void visit(PriorityNode node);
}

AbstractNodeVisitor:

/**
 * @author wangmeng
 * @blog https://www.cnblogs.com/wang-meng/
 * @create 2019-12-01 10:26
 **/
public abstract class AbstractNodeVisitor implements PriorityNodeVisitor{

    private PriorityService priorityService;

    public AbstractNodeVisitor(PriorityService priorityService) {
        this.priorityService = priorityService;
    }

    @Override
    public void visit(PriorityNode node) {
        List<PriorityDTO> priorityDTOList = priorityService.listChildPriorities(node.getId());
        if (CollectionUtils.isNotEmpty(priorityDTOList)) {
            for (PriorityDTO priorityDTO : priorityDTOList) {
                PriorityNode priorityNode = new PriorityNode();
                BeanUtils.copyProperties(priorityDTO, priorityNode);
                // 使用递归处理
                priorityNode.accept(this);
            }
        }

        operateNode(node);
    }

    /**
     * 操作权限树
     * @param node 树节点
     */
    abstract void operateNode(PriorityNode node);
}

PriorityNodeRelateCheckVisitor:

/**
 * 权限树节点的关联检查访问者
 *
 * @author wangmeng
 * @blog https://www.cnblogs.com/wang-meng/
 * @create 2019-12-01 10:19
 **/
public class PriorityNodeRelateCheckVisitor extends AbstractNodeVisitor{

    /**
     * 关联检查结果
     */
    private Boolean relateCheckResult = false;
    /**
     * 权限管理模块的service组件
     */
    private PriorityService priorityService;
    /**
     * 角色和权限关系管理模块的DAO组件
     */
    private RolePriorityRelationshipService rolePriorityRelationshipService;
    /**
     * 账号和权限关系管理模块的Service组件
     */
    private AccountPriorityRelationshipService accountPriorityRelationshipService;

    /**
     * 构造函数
     */
    public PriorityNodeRelateCheckVisitor(PriorityService priorityService,
                                          RolePriorityRelationshipService rolePriorityRelationshipService,
                                          AccountPriorityRelationshipService accountPriorityRelationshipService) {
        super(priorityService);
        this.priorityService = priorityService;
        this.rolePriorityRelationshipService = rolePriorityRelationshipService;
        this.accountPriorityRelationshipService = accountPriorityRelationshipService;
    }

    @Override
    void operateNode(PriorityNode node) {
        Long nodeId = node.getId();
        // 检查权限是否被任何一个角色或者是账号关联了,如果被任何一个角色或者账号关联,则relateCheckResult=true
        int roleRelatedCount = rolePriorityRelationshipService
                .selectCount(new EntityWrapper<RolePriorityRelationship>().eq("priority_id", nodeId));
        if(roleRelatedCount > 0) {
            this.relateCheckResult = true;
        }
        int accountRelatedCount = accountPriorityRelationshipService
                .selectCount(new EntityWrapper<AccountPriorityRelationship>().eq("priority_id", nodeId));
        if(accountRelatedCount > 0) {
            this.relateCheckResult = true;
        }

        this.relateCheckResult = false;
    }

    public Boolean getRelateCheckResult() {
        return relateCheckResult;
    }
}

PriorityNodeRemoveVisitor:

/**
 * 权限树节点的删除访问者
 *
 * @author wangmeng
 * @blog https://www.cnblogs.com/wang-meng/
 * @create 2019-12-01 10:13
 **/
public class PriorityNodeRemoveVisitor extends AbstractNodeVisitor{

    private PriorityService priorityService;

    /**
     * 构造函数
     * @param priorityService 权限service
     */
    public PriorityNodeRemoveVisitor(PriorityService priorityService) {
        super(priorityService);
        this.priorityService = priorityService;
    }

    @Override
    void operateNode(PriorityNode node) {
        // 删除权限
        priorityService.deleteById(node.getId());
    }
}

调用地方 PriorityServiceImpl:

@Override
    public Boolean removePriority(Long id) {
        try {
            // 根据id查询权限
            Priority priorityDO = baseMapper.selectById(id);
            PriorityNode priorityNode = priorityDO.clone(PriorityNode.class);

            // 检查这个权限以及其下任何一个子权限,是否被角色或者账号给关联着
            PriorityNodeRelateCheckVisitor relateCheckVisitor = new PriorityNodeRelateCheckVisitor(
                    this, rolePriorityRelationshipService, accountPriorityRelationshipService);
            relateCheckVisitor.visit(priorityNode);
            Boolean relateCheckResult = relateCheckVisitor.getRelateCheckResult();

            if(relateCheckResult) {
                return false;
            }

            // 递归删除当前权限以及其下所有的子权限
            PriorityNodeRemoveVisitor removeVisitor = new PriorityNodeRemoveVisitor(this);
            removeVisitor.visit(priorityNode);
        } catch (Exception e) {
             log.error("error", e);
            return false;
        }

        return true;
    }

申明: 本文章首发自本人博客:https://www.cnblogs.com/wang-meng 和公众号:壹枝花算不算浪漫 如若转载请标明来源

申明

本文章首发自本人博客:https://www.cnblogs.com/wang-meng 和公众号:壹枝花算不算浪漫,如若转载请标明来源!

感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • SpringBoot测试Service或者Dao层

    要在Spring Boot中使用单元测试是很简单的,Spring Boot提供了spring-boot-starter-test的依赖,即JUnit的相关依赖。

    爱敲代码的猫
  • Python Weekly 423

    链接: https://www.youtube.com/watch?v=P5nOGKVLIYo

    爱写bug
  • 前端技术观察第八期-Chrome79中DevTools的更新

    ConardLi
  • CentOS7下部署KODExplorer可道云个人云盘

    1、下载XAMPP ——XAMPP 是个集成了多个组件的开发环境,包括 Apache + MariaDB + PHP + Perl

    yuanfan2012
  • 我是一个Java Class

    前言:本文主要想讲一下Java虚拟机的故事, 可能有点偏门,不妥之处欢迎留言交流。

    曲水流觞
  • 靶场发展态势③美国防部赛博安全靶场(IAR/CSR)

    美国国防部在2018年依据美国白宫公布的《国家网络战略》(National CyberStrategy),制定其《国防部网络战略》(Department ofD...

    时间之外沉浮事
  • 离线式人脸识别技术,助力智慧社区的建设

    近年来物联网技术快速发展,每一项技术革新,对事物发展都会有巨大促进作用。物联网技术在智能门禁上广泛应用,智能门禁发展如何,对智慧社区建设具有重要影响。在过去智能...

    AI社区
  • 自我量化——使用HealthKit导出运动数据

    今天我们的目标是拿到第一个量化数据:「健身记录」的圆圈数据,即 iPhone 提供的 HealthKit data 数据导出,放入第三方数据库中,以供后续统计和...

    叶梅树
  • 人脸表情识别从0到部署,猜猜『轮到你了』的微笑狼人到底是谁!

    先展示一下我的结果。我们测试的图片当然是当前最热的 nihongo 电视剧『轮到你了』的 CP 二阶堂和黑岛了

    材ccc
  • PHP教程系列5 - 最重要的助手Composer

    Composer是PHP的依赖管理工具,诞生的时间比较晚,在PHP5.3才正式发布。发布之后不温不火,支持的包也少,一度被认为是下一个pecl(比较失败的工具)...

    sibenx

扫码关注云+社区

领取腾讯云代金券