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


    前言

    申明:
    本文章首发自本人博客: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. 实现类图
      09D8AF63-1056-42EA-A65A-833B55F9BA6A.png

    2. 代码实现
      这里使用访问者模式 分开一个检查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 和公众号:壹枝花算不算浪漫,如若转载请标明来源!

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

    22.jpg

  • 相关阅读:
    递归实现全排列问题
    LeetCode
    LeetCode
    连续子元素最大和
    简单模板view调用
    如何清除PHP中不需要的Layout模板
    Model中设置表单验证方法
    数据修改操作
    MVC模式tp框架四中路由形式
    zend Framework的MVC模式的搭建
  • 原文地址:https://www.cnblogs.com/wang-meng/p/11982661.html
Copyright © 2020-2023  润新知