【一起学设计模式】访问者模式实战:权限管理树删除节点操作
前言
申明:
本文章首发自本人博客:https://www.cnblogs.com/wang-meng 和公众号:壹枝花算不算浪漫 如若转载请标明来源
之前在我的博客(一枝花算不算浪漫)中已经更新过两篇设计模式相关的内容
上面内容都是基于真实业务场景精简后的设计(工作中真实场景使用到的)。
之前为了学习设计模式,看过网上很多相关博客讲解,大都是画下UML类图,举例几个毫不相干的demo,看了几遍仍然是云里雾里。
学习设计模式只有在真正的业务场景去使用才会更好的理解其精髓。这里举例自己工作中电商的业务场景,然后配合一些业务功能的实现,来学会设计模式,使自己的代码更优雅。
业务背景
权限功能模块-权限树-删除树上的某个权限
- 要求判断该权限节点及其子节点是否有用户、角色关联,如若有关联则不允许删除
- 要求删除该权限节点及其子节点所有数据
常规操作
先说下大多数人为了实现需求都会做的常规操作,这里举例说明,权限A,其子节点B、C
- 查找权限A是否被用户、角色关联过
- 查找全新啊A下面所有子节点B、C
- 查找权限B、C是否被其他用户、角色关联过
- 删除A、B、C
这里如果有个流程图效果会更佳,但是相信大家看到文字也能明白其中的运转流程。
这里只是简单地列了下操作的步骤,其实大家可能会做的更好,比如查询、删除 都可以批量去做处理,这里就不再讨论了。
通过上面的流程,我们知道一个方法就可以搞定这几个步骤,只是该方法包含了查询、删除等等逻辑操作,看起来并不精简。
访问者模式实现
-
实现类图
-
代码实现
这里使用访问者模式 分开一个检查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 和公众号:壹枝花算不算浪漫,如若转载请标明来源!
感兴趣的小伙伴可关注个人公众号:壹枝花算不算浪漫