节点接口-Node
# 🎯 简介
Node 是 Hutool 树结构模块中的核心接口,定义了树节点的基本行为和属性。它是所有树节点类的基础,提供了节点 ID、父节点 ID、节点名称、权重等基本属性的访问方法,并实现了 Comparable 接口用于节点排序。
# 📋 核心特性
- ✅ 泛型设计,支持任意类型的 ID
- ✅ 定义了节点的基本属性(ID、父ID、名称、权重)
- ✅ 支持链式调用,使用更便捷
- ✅ 实现了
Comparable接口,可直接用于排序 - ✅ 实现了
Serializable接口,支持序列化 - ✅ 提供默认的
compareTo实现,基于权重排序 - ✅ 接口设计简洁,易于实现
- ✅ 是所有树节点类的基础接口
# 🛠️ 接口结构
typedef Node<T>
├── 继承自 Comparable<Node<T>>, Serializable
└── 方法
├── getId(): T // 获取节点ID
├── setId(id): Node<T> // 设置节点ID(链式)
├── getParentId(): T // 获取父节点ID
├── setParentId(parentId): Node<T> // 设置父节点ID(链式)
├── getName(): CharSequence // 获取节点名称
├── setName(name): Node<T> // 设置节点名称(链式)
├── getWeight(): Comparable<?> // 获取权重
├── setWeight(weight): Node<T> // 设置权重(链式)
└── compareTo(node): int // 比较两个节点,基于权重排序
# 🚀 快速开始
# 实现Node接口
// 实现Node接口
class MyNode implements Node<String> {
private String id;
private String parentId;
private String name;
private Integer weight;
// 构造方法省略
@Override
public String getId() {
return id;
}
@Override
public Node<String> setId(String id) {
this.id = id;
return this;
}
@Override
public String getParentId() {
return parentId;
}
@Override
public Node<String> setParentId(String parentId) {
this.parentId = parentId;
return this;
}
@Override
public CharSequence getName() {
return name;
}
@Override
public Node<String> setName(CharSequence name) {
this.name = name.toString();
return this;
}
@Override
public Comparable<?> getWeight() {
return weight;
}
@Override
public Node<String> setWeight(Comparable<?> weight) {
this.weight = (Integer) weight;
return this;
}
}
// 使用自定义节点
MyNode root = new MyNode();
root.setId("1")
.setParentId("0")
.setName("根节点")
.setWeight(0);
MyNode child = new MyNode();
child.setId("2")
.setParentId("1")
.setName("子节点")
.setWeight(1);
Console.log("根节点: {}", root);
Console.log("子节点: {}", child);
# 使用已有实现类
// 使用TreeNode实现类
TreeNode<Long> node = new TreeNode<>();
node.setId(1L)
.setParentId(0L)
.setName("节点1")
.setWeight(5);
// 使用MapTree实现类
MapTree<String> mapTree = new MapTree<>();
mapTree.setId("1")
.setParentId("0")
.setName("Map节点")
.setWeight(3);
// 比较节点
int compareResult = node.compareTo(mapTree);
Console.log("节点比较结果: {}", compareResult);
# 📖 详细方法
# getId()
功能:获取节点ID
返回值:节点ID,类型为泛型T
示例:
String id = node.getId();
# setId(id)
功能:设置节点ID
参数:
id- 节点ID返回值:当前节点实例,支持链式调用
示例:
node.setId("1");
# getParentId()
功能:获取父节点ID
返回值:父节点ID,类型为泛型T
示例:
String parentId = node.getParentId();
# setParentId(parentId)
功能:设置父节点ID
参数:
parentId- 父节点ID返回值:当前节点实例,支持链式调用
示例:
node.setParentId("0");
# getName()
功能:获取节点名称
返回值:节点名称,类型为CharSequence
示例:
CharSequence name = node.getName();
# setName(name)
功能:设置节点名称
参数:
name- 节点名称返回值:当前节点实例,支持链式调用
示例:
node.setName("节点名称");
# getWeight()
功能:获取节点权重
返回值:节点权重,类型为Comparable<?>
示例:
Comparable<?> weight = node.getWeight();
# setWeight(weight)
功能:设置节点权重
参数:
weight- 节点权重,用于排序返回值:当前节点实例,支持链式调用
示例:
node.setWeight(5);
# compareTo(node)
功能:比较两个节点,基于权重排序
参数:
node- 要比较的节点返回值:比较结果,负数表示当前节点小于参数节点,0表示相等,正数表示当前节点大于参数节点
默认实现:基于权重比较,如果权重相同则比较节点对象
示例:
int result = node1.compareTo(node2);
# 🎨 使用场景
# 1. 自定义节点类型
// 定义部门节点
class DepartmentNode implements Node<Long> {
private Long id;
private Long parentId;
private String name;
private Integer orderNum;
private String deptCode;
private String leader;
// 构造方法省略
// 实现Node接口方法
@Override
public Long getId() {
return id;
}
@Override
public Node<Long> setId(Long id) {
this.id = id;
return this;
}
@Override
public Long getParentId() {
return parentId;
}
@Override
public Node<Long> setParentId(Long parentId) {
this.parentId = parentId;
return this;
}
@Override
public CharSequence getName() {
return name;
}
@Override
public Node<Long> setName(CharSequence name) {
this.name = name.toString();
return this;
}
@Override
public Comparable<?> getWeight() {
return orderNum;
}
@Override
public Node<Long> setWeight(Comparable<?> weight) {
this.orderNum = (Integer) weight;
return this;
}
// 自定义方法
public String getDeptCode() {
return deptCode;
}
public DepartmentNode setDeptCode(String deptCode) {
this.deptCode = deptCode;
return this;
}
public String getLeader() {
return leader;
}
public DepartmentNode setLeader(String leader) {
this.leader = leader;
return this;
}
}
// 使用自定义部门节点
DepartmentNode deptNode = new DepartmentNode();
deptNode.setId(1L)
.setParentId(0L)
.setName("技术部")
.setWeight(1)
.setDeptCode("TECH")
.setLeader("张经理");
Console.log("部门节点: {}", deptNode);
# 2. 节点排序
// 创建节点列表
List<Node<Long>> nodeList = new ArrayList<>();
// 添加节点
nodeList.add(new TreeNode<Long>().setId(1L).setParentId(0L).setName("节点1").setWeight(3));
nodeList.add(new TreeNode<Long>().setId(2L).setParentId(0L).setName("节点2").setWeight(1));
nodeList.add(new TreeNode<Long>().setId(3L).setParentId(0L).setName("节点3").setWeight(5));
nodeList.add(new TreeNode<Long>().setId(4L).setParentId(0L).setName("节点4").setWeight(2));
// 排序节点
nodeList.sort(Comparator.naturalOrder());
// 输出排序结果
Console.log("排序后的节点列表: {}", nodeList);
# 3. 树结构构建
// 定义产品分类节点
class CategoryNode implements Node<String> {
private String id;
private String parentId;
private String name;
private Integer sortOrder;
private List<CategoryNode> children;
// 构造方法、getter和setter省略
// 实现Node接口方法
@Override
public String getId() {
return id;
}
@Override
public Node<String> setId(String id) {
this.id = id;
return this;
}
@Override
public String getParentId() {
return parentId;
}
@Override
public Node<String> setParentId(String parentId) {
this.parentId = parentId;
return this;
}
@Override
public CharSequence getName() {
return name;
}
@Override
public Node<String> setName(CharSequence name) {
this.name = name.toString();
return this;
}
@Override
public Comparable<?> getWeight() {
return sortOrder;
}
@Override
public Node<String> setWeight(Comparable<?> weight) {
this.sortOrder = (Integer) weight;
return this;
}
}
// 创建分类节点列表
List<CategoryNode> categoryList = new ArrayList<>();
categoryList.add(new CategoryNode("1", "0", "电子产品", 1, new ArrayList<>()));
categoryList.add(new CategoryNode("2", "1", "手机", 1, new ArrayList<>()));
categoryList.add(new CategoryNode("3", "1", "电脑", 2, new ArrayList<>()));
categoryList.add(new CategoryNode("4", "2", "智能手机", 1, new ArrayList<>()));
categoryList.add(new CategoryNode("5", "2", "功能手机", 2, new ArrayList<>()));
// 构建分类树
List<CategoryNode> categoryTree = buildTree(categoryList, "0");
Console.log("分类树: {}", categoryTree);
// 简单的树构建方法
private List<CategoryNode> buildTree(List<CategoryNode> nodeList, String rootId) {
List<CategoryNode> tree = new ArrayList<>();
for (CategoryNode node : nodeList) {
if (rootId.equals(node.getParentId())) {
// 递归构建子树
node.setChildren(buildTree(nodeList, node.getId()));
tree.add(node);
}
}
// 排序子节点
tree.sort(Comparator.naturalOrder());
return tree;
}
# 💡 注意事项
泛型类型:
T是节点ID的类型,建议使用不可变类型(如Long、String)- 确保所有节点的ID类型一致,否则会导致类型转换错误
权重排序:
- 默认的
compareTo方法基于权重比较 - 权重值越小,节点优先级越高
- 如果权重为null,比较结果可能不符合预期,建议始终设置权重
- 默认的
链式调用:
- 所有setter方法都返回当前节点实例,支持链式调用
- 链式调用可以提高代码可读性和编写效率
实现类:
- Hutool提供了两个主要实现类:
TreeNode和MapTree TreeNode是简单的POJO实现MapTree是基于Map的动态属性实现
- Hutool提供了两个主要实现类:
序列化:
- 实现了
Serializable接口,支持序列化和反序列化 - 自定义实现类时,需要确保所有属性都支持序列化
- 实现了
equals和hashCode:
- 接口本身没有定义
equals和hashCode方法 - 自定义实现类时,建议根据ID重写这两个方法
- 接口本身没有定义
# 🚀 性能优化
- 对于大量节点的场景,建议使用基本类型作为权重,提高比较效率
- 实现类中应避免在getter方法中进行复杂计算
- 对于频繁比较的场景,考虑缓存比较结果
# 🔍 最佳实践
接口设计:
- 自定义实现类时,建议遵循接口的方法签名
- 保持setter方法的链式调用特性
权重设计:
- 根据业务需求合理设计权重规则
- 权重值应具有明确的业务含义
- 建议使用整数类型作为权重,便于比较和排序
ID选择:
- 选择合适的ID类型(如Long、String、UUID)
- 确保ID的唯一性和稳定性
继承关系:
- 对于复杂的节点类型,考虑继承已有实现类(如TreeNode)
- 避免直接实现接口,减少重复代码
排序使用:
- 利用接口的
Comparable实现,方便节点排序 - 结合Stream API使用,提高代码简洁性
- 利用接口的
# 📝 总结
Node 接口是 Hutool 树结构模块的核心,定义了树节点的基本行为和属性。它的设计简洁明了,易于实现和使用,为树结构的构建和操作提供了基础。
通过实现 Node 接口,可以创建各种类型的树节点,满足不同业务场景的需求。同时,接口提供的默认 compareTo 实现,使得节点可以直接用于排序,简化了树结构的处理。
在实际开发中,建议优先使用 Hutool 提供的实现类(TreeNode 和 MapTree),如果需要自定义节点类型,可以继承这些实现类或直接实现 Node 接口。
Node 接口的设计体现了面向接口编程的思想,使得树结构的实现更加灵活和可扩展。无论是构建简单的菜单树,还是复杂的组织架构树,Node 接口都能提供可靠的支持。