我们通常会在应用中碰到树形结构的内容,比如 文件夹/文件模型, 部门组织结构,目录树等等,通常在设计模式中叫做 compose 模式。
在数据库中常常这样表示: 我们以Catalog (分级目录) 为例子
Catalog (分级目录)
|
字段名称
|
字段
|
类型
|
备注
|
目录ID
|
catalog_id
|
varchar(36)
|
pk, not null
|
目录名称
|
catalog_name
|
varchar(50)
|
not null
|
父目录ID
|
parent_id
|
varchar(36)
|
fk
|
创建时间
|
create_datetime
|
datetime
|
not null
|
目录描述
|
description
|
varchar(200)
|
|
我们考虑在数据库中一次将所有数据读入内存,然后在内存中生成一个Tree,这样可以减少数据库的访问,增加性能,并且只有的数据方式改变的时候,全部重新从数据库中生成Tree,否则一直保持在内存中。
我们使用标准的DAO模式先生成 POJO类(Catalog)和DAO类(CatalogDAO)。
然后我们建立相对通用的 Tree 和 TreeNode 类。
Tree.java
package com.humpic.helper.tree;
import java.util.*;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
public abstract class Tree {
protected static Log log = LogFactory.getLog(Tree.class);
private Map treeNodeMaps = new Hashtable();
private TreeNode root;
/**
* root if it's parent is empty
*/
protected void reload(List nodes) {
log.info("tree will start reload all data");
synchronized (this) {
// initialize
treeNodeMaps.clear();
root = null;
List treeNodes = new Vector(nodes.size());
for (int i = 0; i < nodes.size(); i++) {
TreeNode node = this.transform(nodes.get(i)); // transform
treeNodes.add(node);
node.setTree(this);
treeNodeMaps.put(node.getNodeId(), node);
}
for (int i = 0; i < treeNodes.size(); i++) {
TreeNode node = (TreeNode) treeNodes.get(i);
String parentId = node.getParentId();
if (this.isRootNode(node)) {
if (root == null) {
root = node;
} else {
log.error("find more then one root node. ignore.");
}
} else {
TreeNode parent = (TreeNode) treeNodeMaps.get(parentId);
if (parent != null) {
parent.addChild(node);
node.setParent(parent);
} else {
log.warn("node [id=" + node.getNodeId() + "]: missing parent node.");
}
}
}
}
if (root == null) {
log.error("the root node is not be defined");
}
}
protected boolean isRootNode(TreeNode node) {
return StringUtils.isBlank(node.getParentId());
}
public TreeNode getRootNode() {
return root;
}
public TreeNode getTreeNode(String nodeId) {
return (TreeNode) treeNodeMaps.get(nodeId);
}
public void addTreeNode(TreeNode node) {
synchronized (this) {
treeNodeMaps.put(node.getNodeId(), node);
String parentId = node.getParentId();
if (StringUtils.isNotBlank(parentId)) {
TreeNode parent = getTreeNode(parentId);
if (parent != null) {
parent.addChild(node);
node.setParent(parent);
} else {
log.error("parent cannot be found: " + node.getParentId());
}
} else {
if (root == null) {
root = node;
} else {
log.error("find more then one root node. ignore.");
}
}
}
}
public void deleteTreeNode(String nodeId) {
synchronized (this) {
TreeNode node = getTreeNode(nodeId);
if (node == null)
throw new IllegalArgumentException(nodeId + " cannot be found.");
if (node.getParent() == null) {
root = null;
treeNodeMaps.clear();
log.warn("the root node has been removed.");
} else {
node.getParent().getChildren().remove(node);
treeNodeMaps.remove(nodeId);
List children = node.getAllChildren();
for (int i = 0; i < children.size(); i++) {
TreeNode n = (TreeNode) children.get(i);
treeNodeMaps.remove(n.getNodeId());
}
}
}
}
/**
* <pre>
* Usage: Office ->
*
* public TreeNode transform(Object info) {
* OfficeInfo office_info = (OfficeInfo) info;
* TreeNode node = new TreeNode();
* node.setNodeId(office_info.getOfficeId());
* node.setParentId(office_info.getParentId());
* node.setBindData(office_info);
* return node;
* }
* </pre>
*/
protected abstract TreeNode transform(Object info);
}
TreeNode.java
package com.humpic.helper.tree;
import java.util.List;
import java.util.Vector;
import org.apache.commons.collections.Predicate;
import org.apache.commons.lang.ObjectUtils;
public class TreeNode {
private Tree tree;
private TreeNode parent;
private List children = new Vector();
private List childrenGroup = new Vector();
private String nodeId;
private String parentId;
private Object bindData;
public String getNodeId() {
return nodeId;
}
public void setNodeId(String nodeId) {
this.nodeId = nodeId;
}
public String getParentId() {
return parentId;
}
public void setParentId(String parentId) {
this.parentId = parentId;
}
public Object getBindData() {
return bindData;
}
public void setBindData(Object bindData) {
this.bindData = bindData;
}
public Tree getTree() {
return tree;
}
public void setTree(Tree tree) {
this.tree = tree;
}
public void setParent(TreeNode parent) {
this.parent = parent;
}
public TreeNode getParent() {
return this.parent;
}
public List getChildren() {
return this.children;
}
public void addChild(TreeNode node) {
children.add(node);
}
/**
* get all children, and chilren's children
*/
public List getAllChildren() {
if (this.childrenGroup.isEmpty()) {
synchronized (this.tree) {
for (int i = 0; i < this.children.size(); i++) {
TreeNode node = (TreeNode) this.children.get(i);
this.childrenGroup.add(node);
this.childrenGroup.addAll(node.getAllChildren());
}
}
}
return this.childrenGroup;
}
/**
* get all children, and chilren's children
*/
public List getAllChildren(Predicate predicate) {
List groups = new Vector();
fillAllChildren(groups, predicate);
return groups;
}
private void fillAllChildren(List groups, Predicate predicate) {
for (int i = 0; i < this.children.size(); i++) {
TreeNode node = (TreeNode) this.children.get(i);
if (predicate.evaluate(node)) {
groups.add(node);
node.fillAllChildren(groups, predicate);
}
}
}
/**
* get all parents, and parent's parent
*/
public List getParents() {
List results = new Vector();
TreeNode parent = this.getParent();
while (parent != null) {
results.add(parent);
parent = parent.getParent();
}
return results;
}
/**
* A.isMyParent(B) == B is A' parent ? <br>
* root.isMyParent(null) == true; <br>
* root.isMyParent(*) == false <br>
* *.isMyParent(null) == false
*/
public boolean isMyParent(String nodeId) {
TreeNode target = tree.getTreeNode(nodeId);
TreeNode parent = this.getParent();
if (parent == null) {
return target == null;
} else {
return parent.equals(target);
}
}
/**
* A.isMyAncestor(B) == B is A' ancestor ? <br>
* *.isMyAncestor(null) == true;
*/
public boolean isMyAncestor(String nodeId) {
TreeNode target = tree.getTreeNode(nodeId);
if (target == null)
return true;
return target.getAllChildren().contains(this);
}
/**
* A.isMyBrother(B) == B is A' brother ? <br>
* *.isMyBrother(null) == false
*/
public boolean isMyBrother(String nodeId) {
TreeNode target = tree.getTreeNode(nodeId);
if (target == null)
return false;
TreeNode p1 = this.getParent();
TreeNode p2 = target.getParent();
return ObjectUtils.equals(p1, p2);
}
}
然后建立业务 Tree
CatalogTree.java
package com.humpic.helper.tree;
import java.util.List;
import org.apache.commons.collections.Predicate;
public class CatalogTree extends Tree {
private static CatalogTree instance = null;
private CatalogTree() {}
public static synchronized CatalogTree getInstance() {
if (instance == null) {
instance = new CatalogTree();
instance.reloadCatalogs();
}
return instance;
}
protected TreeNode transform(Object info) {
Catalog catalog = (Catalog) info;
TreeNode node = new TreeNode();
node.setNodeId(catalog.getCatalogId());
node.setParentId(catalog.getParentId());
node.setBindData(catalog);
return node;
}
public void reloadCatalogs() {
List nodes = CatalogDAO.getInstance().findAll();
super.reload(nodes);
}
public Catalog getCatalogNode(String catalogId) {
TreeNode node = super.getTreeNode(catalogId);
return node == null ? null : (Catalog) node.getBindData();
}
}
最后,我们只要使用以下的语句就可以了:
1. CatalogTree.getInstance().getTreeNode(...)
2. CatalogTree.getInstance().getCatalogNode(...)
3. CatalogTree.getInstance().getRootNode()
然后通过 TreeNode,就可以得到 parent, parents 和 children, allChildren
分享到:
相关推荐
在Java递归树型结构通用数据库中,使用关系型数据库来存储部门信息,数据库表结构设计包括部门表、用户表、部门用户表等,通过这些表之间的关系实现树型结构的部门管理。 6. 递归算法实现 在Java递归树型结构通用...
在计算机科学中,树形结构常用于表示文件系统、网页链接、数据库索引、表达式解析、任务调度等多种场景。 在JavaScript中实现树形结构,一般会涉及到以下几个核心概念: 1. 节点(Node):树的基本单元,通常包含...
这里,我们探讨的是如何通过Hibernate来抽象和扩展Java中的树形结构,并考虑到了在数据库表设计时的灵活性。 首先,我们看到一个具体的树形结构实体类`Modual2`,它代表了一个模块,具有ID(dbid)、名称(nane)、...
2. **树形结构**:树和二叉树的概念,以及它们在查找和排序操作中的应用,例如二叉搜索树、AVL树、堆等。 3. **图结构**:图的表示方法,包括邻接矩阵和邻接表,以及图的遍历算法,如深度优先搜索(DFS)和广度优先...
综上所述,该决赛试题主要考察了 Java 语言基础(如 `BigInteger` 类的使用)、数据结构(树形结构的构建和表示)、程序设计原则(代码的通用性、正确性)以及编程规范,同时也涉及到了问题解决和算法设计的能力。...
Java开发过程中,jar(Java Archive)包是必不可少的资源,它们包含了预编译的类、接口和其他资源,方便开发者在项目中直接引用。本压缩包集合涵盖了多种实用的jar包,旨在提供对不同数据库的连接支持,SSH(Spring...
DOM将整个XML文档加载到内存中,形成一个树形结构,适合小规模数据处理。SAX是事件驱动的解析器,逐个处理XML元素,节省内存,适合大文件。StAX则允许程序员以流式方式读写XML,提供更好的性能和控制。 2. **JDBC...
- 树形结构、图结构等高级数据结构 - **学习资源**: - 数据结构教材(适合大二学生) **1.3 Java集合框架** - **定义**: Java集合框架是一套用于存储和操作对象集合的标准API,提供了多种数据结构实现。 - **内容...
- **组合模式**:允许你将对象组合成树形结构来表现“整体/部分”层次结构,使得用户对单个对象和组合对象的使用具有一致性。 - **装饰器模式**:动态地给一个对象添加一些额外的职责,可以提供比继承更具弹性的...
通常,菜单结构会被设计成树形结构,便于层次化展示。菜单与权限管理紧密关联,用户看到的菜单由其角色所拥有的权限决定。这部分可能涉及到前端的路由配置,例如使用React Router或Vue Router来实现。 【技术栈】:...
我们的目标是将这个列表转换为树形结构,这样可以更好地体现数据间的层次关系。 对于非递归方法,我们可以利用栈或队列等数据结构来实现。这种方法避免了递归可能导致的堆栈溢出问题,尤其适用于层级较深的树结构。...
6. **组合模式**:允许你将对象组合成树形结构来表现“整体/部分”层次结构。在Java UI组件树中广泛应用。 7. **装饰器模式**:动态地给一个对象添加一些额外的职责。Java的IO流体系结构就是装饰器模式的经典应用。...
组合模式(Composite)将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 代理模式(Proxy)为其他对象提供一个代理以控制对这个对象的访问。代理模式...
需要修改Hibernate的配置信息,并创建一个与数据库表同名的Java Bean类和一个Vo类并继承Vo(类名:数据库表名+Vo) 将代码部署在服务器上后,访问index.jsp,输入类名和分页大小,就可以生成该表的树形目录
标题中的“树形菜单tag框架 非树形的点击事件”指的是在Web开发中,如何在非树形结构的菜单系统中实现类似树形菜单的点击事件处理。树形菜单通常用于展示层级关系的数据,而这里的“非树形”的含义可能是指在没有...
- **层次型数据库**:以树形结构组织数据,记录间通过指针关联,适用于特定场景,但查询和更新操作复杂。 - **网状数据库**:以网格结构表示实体,支持多对多联系,但应用程序编写复杂。 - **关系型数据库**:...
1. **增加系统资源信息和操作类型信息**:系统资源形成树形结构,如销售模块、销售订单等;操作类型记录各种可能的操作,如增加、删除等。 2. **增加数据对象类型和数据对象表**:数据对象类型记录需控制的对象类型...
10. **组合模式**:将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。在Java UI框架中,如Swing和JavaFX,组件树就是一个典型的组合模式应用。 以上只是设计...
本主题将深入探讨如何使用Java集合、JSP和JSTL来递归地创建并输出树形结构(Tree),特别是用于前端展示。 首先,我们要理解Java集合在构建树结构中的作用。在Java中,可以使用ArrayList、LinkedList或者自定义的...