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

前言

申明:
本文章首發自本人博客:https://www.cnblogs.com/wang-meng 和公衆號:壹枝花算不算浪漫 如若轉載請標明來源html

以前在個人博客(一枝花算不算浪漫)中已經更新過兩篇設計模式相關的內容java

上面內容都是基於真實業務場景精簡後的設計(工做中真實場景使用到的)。node

以前爲了學習設計模式,看過網上不少相關博客講解,大都是畫下UML類圖,舉例幾個絕不相干的demo,看了幾遍仍然是雲裏霧裏。設計模式

學習設計模式只有在真正的業務場景去使用纔會更好的理解其精髓。這裏舉例本身工做中電商的業務場景,而後配合一些業務功能的實現,來學會設計模式,使本身的代碼更優雅。app

業務背景

權限功能模塊-權限樹-刪除樹上的某個權限ide

  1. 要求判斷該權限節點及其子節點是否有用戶、角色關聯,如如有關聯則不容許刪除
  2. 要求刪除該權限節點及其子節點全部數據

常規操做

先說下大多數人爲了實現需求都會作的常規操做,這裏舉例說明,權限A,其子節點B、C函數

  1. 查找權限A是否被用戶、角色關聯過
  2. 查找全新啊A下面全部子節點B、C
  3. 查找權限B、C是否被其餘用戶、角色關聯過
  4. 刪除A、B、C

這裏若是有個流程圖效果會更佳,可是相信你們看到文字也能明白其中的運轉流程。學習

這裏只是簡單地列了下操做的步驟,其實你們可能會作的更好,好比查詢、刪除 均可以批量去作處理,這裏就再也不討論了。this

經過上面的流程,咱們知道一個方法就能夠搞定這幾個步驟,只是該方法包含了查詢、刪除等等邏輯操做,看起來並不精簡。url

訪問者模式實現

  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

相關文章
相關標籤/搜索