【一起學設計模式】訪問者模式實戰:權限管理樹刪除節點操作


前言

申明:
本文章首發自本人博客: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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM