组合模式:

对层级数据递归调用执行操作

我们要对部门树,删除一个父部门以及其下所有的子部门
系的那种场景,比如部门树的递归删除,或者是文件树的递归删除之类的场景。
访问者模式:

访问者模式,是对目标对象,动态的执行某个功能,而不对目标对象有任何的改动。

访问者和组合模式天然适合组合起来使用。

需求场景:
一个管理系统里面有很多种权限:
一种权限可以被多个角色拥有
一个角色和权限目前可以关联多个账号

然后我们执行一个权限的删除操作时,有2个需求:

1、先判断这个权限是否还存在关联的角色或者账号,如果存在在不能删除,不存在关联的了则可以删除

2、删除一个权限则要递归删除它的所有子权限

对于以上1、2 我们就可以使用组合模式构建权限树、然后通过访问者模式来进行判断关联以及删除。

首先定义一个访问者接口,不同的访问者实现类,会在被访问对象里执行不同的操作, public void accept(PriorityNodeVisitor visitor) 方法接收一个访问者

/**
 * 权限树节点的访问者接口
 * @author 
 *
 */
public interface PriorityNodeVisitor {

	/**
	 * 访问权限树节点
	 * @param node 权限树节点
	 */
	void visit(PriorityNode node);
	
}

组合模式的权限树


/**
 * 权限树节点
 * @author 
 *
 */
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);  
	}
	
	public Long getId() {
		return id;
	}
	public void setId(Long id) {
		this.id = id;
	}
	public String getCode() {
		return code;
	}
	public void setCode(String code) {
		this.code = code;
	}
	public String getUrl() {
		return url;
	}
	public void setUrl(String url) {
		this.url = url;
	}
	public String getPriorityComment() {
		return priorityComment;
	}
	public void setPriorityComment(String priorityComment) {
		this.priorityComment = priorityComment;
	}
	public Integer getPriorityType() {
		return priorityType;
	}
	public void setPriorityType(Integer priorityType) {
		this.priorityType = priorityType;
	}
	public Long getParentId() {
		return parentId;
	}
	public void setParentId(Long parentId) {
		this.parentId = parentId;
	}
	public Date getGmtCreate() {
		return gmtCreate;
	}
	public void setGmtCreate(Date gmtCreate) {
		this.gmtCreate = gmtCreate;
	}
	public Date getGmtModified() {
		return gmtModified;
	}
	public void setGmtModified(Date gmtModified) {
		this.gmtModified = gmtModified;
	}
	public List<PriorityNode> getChildren() {
		return children;
	}
	public void setChildren(List<PriorityNode> children) {
		this.children = children;
	}
	
}

访问者实现类1:
完成权限节点检查的访问者,通过 public Boolean getRelateCheckResult() 获取访问完的结果。

/**
 * 权限树节点的关联检查访问者
 * @author
 *
 */
public class PriorityNodeRelateCheckVisitor implements PriorityNodeVisitor {

	/**
	 * 关联检查结果
	 */
	private Boolean relateCheckResult = false;
	/**
	 * 权限管理模块的DAO组件
	 */
	private PriorityDAO priorityDAO;
	/**
	 * 角色和权限关系管理模块的DAO组件
	 */
	private RolePriorityRelationshipDAO rolePriorityRelationshipDAO;
	/**
	 * 账号和权限关系管理模块的DAO组件
	 */
	private AccountPriorityRelationshipDAO accountPriorityRelationshipDAO;
	
	/**
	 * 构造函数
	 * @param priorityDAO 权限管理模块的DAO组件
	 * @param rolePriorityRelationshipDAO 角色和权限关系管理模块的DAO组件
	 * @param accountPriorityRelationshipDAO 账号和权限关系管理模块的DAO组件
	 */
	public PriorityNodeRelateCheckVisitor(
			PriorityDAO priorityDAO,
			RolePriorityRelationshipDAO rolePriorityRelationshipDAO,
			AccountPriorityRelationshipDAO accountPriorityRelationshipDAO) {
		this.priorityDAO = priorityDAO;
		this.rolePriorityRelationshipDAO = rolePriorityRelationshipDAO;
		this.accountPriorityRelationshipDAO = accountPriorityRelationshipDAO;
	}
	
	/**
	 * 访问权限树节点
	 */
	@Override
	public void visit(PriorityNode node) {
         List<PriorityDO> priorityDOs = priorityDAO.listChildPriorities(node.getId());
         if (priorityDOs != null && priorityDOs.size() > 0) {
         	for (PriorityDO priorityDO : priorityDOs) {
         		PriorityNode priorityNode = priorityDO.clone(PriorityNode.class);
         		priorityNode.accept(this);
			}
		 }
         if (relateCheck(node)) {
         	this.relateCheckResult = true;
		 }
	}
	
	/**
	 * 检查权限是否被任何一个角色或者是账号关联了 
	 * @param node 权限树节点
	 * @return 是否被任何一个角色或者是账号关联了,如果有关联则为true;如果没有关联则为false
	 */
	private Boolean relateCheck(PriorityNode node) {
		Long roleRelatedCount = rolePriorityRelationshipDAO.getCountByPriorityId(node.getId());
		if (roleRelatedCount != null && roleRelatedCount > 0) {
			return true;
		}

		Long accountRelatedCount = accountPriorityRelationshipDAO
				.getCountByPriorityId(node.getId());
		if(accountRelatedCount != null && accountRelatedCount > 0) {
			return true;
		}
		return false;
	}

	public Boolean getRelateCheckResult() {
		return relateCheckResult;
	}
	
}

访问者实现类2:
查询节点的子节点,进行递归删除

/**
 * 递归删除访问者
 */
public class PriorityNodeRemoveVisitor implements PriorityNodeVisitor {
    /**
     * 权限管理模块的DAO组件
     */
    private PriorityDAO priorityDAO;

    /**
     * 构造函数
     * @param priorityDAO 权限管理模块的DAO组件
     */
    public PriorityNodeRemoveVisitor(PriorityDAO priorityDAO) {
        this.priorityDAO = priorityDAO;
    }

    /**
     * 访问权限树节点
     * @param node 权限树节点
     */
    @Override
    public void visit(PriorityNode node) {
        List<PriorityDO> priorityDOs = priorityDAO
                .listChildPriorities(node.getId());
        if(priorityDOs != null && priorityDOs.size() > 0) {
            for(PriorityDO priorityDO : priorityDOs) {
                PriorityNode priorityNode = priorityDO.clone(PriorityNode.class);
                priorityNode.accept(this);
            }
        }
        removePriority(node);
    }

    /**
     * 删除权限
     * @param node 权限树节点
     */
    private void removePriority(PriorityNode node) {
        priorityDAO.removePriority(node.getId());
    }

}

使用示例:

@Override
	public Boolean removePriority(Long id) {
		try {
			// 根据id查询权限
			PriorityDO priorityDO = priorityDAO.getPriorityById(id);
			PriorityNode priorityNode = priorityDO.clone(PriorityNode.class);

			// 检查这个权限以及其下任何一个子权限,是否被角色或者账号给关联着
			PriorityNodeRelateCheckVisitor relateCheckVisitor = new PriorityNodeRelateCheckVisitor(
					priorityDAO, rolePriorityRelationshipDAO, accountPriorityRelationshipDAO
			);
			relateCheckVisitor.visit(priorityNode);
			Boolean relateCheckResult = relateCheckVisitor.getRelateCheckResult();
			if (relateCheckResult) {
				return false;
			}
			PriorityNodeRemoveVisitor removeVisitor = new PriorityNodeRemoveVisitor(priorityDAO);
			removeVisitor.visit(priorityNode);
		} catch (Exception e) {
			logger.error("error:", e);
			return false;
		}
		return true;
	}