前言
申明:
本文章首發自本人博客: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 和公眾號:壹枝花算不算浪漫,如若轉載請標明來源!
感興趣的小伙伴可關注個人公眾號:壹枝花算不算浪漫