程序开发中经常会用到树型结构,如组织机构·菜单·角色(支持继承的角色)·分目录的参数管理。
下面是我的一段经历,来单位不久我被分配到一个客服平台开发的项目中,由一位‘资深’项目经理带着做,他已经有五到六年的工作经验
了,不过在后来的工作中发现,他这六年是ctrl+c,ctrl+v过来的。
切入正题,我负责的模块中有一个是知识库的建立与应用,它的需求是这样的,要有一个目录,目录里有子目录,共要求三级目录,目录下
面对应着的是一些业务知识点供客服人员查看。
之前我没有用过树型结构,在这个程序里他们有写好的树型结构的读取工具,我看了看,大致如下做法是在后台组织一个html,然后发送到
前台再用js工具进行格式化成树的模样,具体操作是读很多次数据库数据,如果有三级就先读取一级结点,然后读取二级结点,再读取三级
结点。采用的是深度优先的做法把数据读取出来,在读取的时候组装html。
我看了以后头很大,因为我想用他们现有的模式去做,心里会很不舒服:
他们的做法有很多不足
1.在组装树型结构的时候会查询多次数据库,而且随着结点数目的增长,查询次数也随之增长很多。
2.不便于调试,有了问题很难发现。
3.不便于数据缓存。
4.增加网络流量。
5.针对一个js树型工具组装的html,如果换成其他的js工具几乎是不可能的。
6.代码没有可重用性,它把业务数据库与组装html混合在一起。
7.如果数据库数据出现循环引用,会在死循环里出不来,还有可能导致系统崩溃。
....
为了解决上述问题,我自己写了一个简单的树型结构加载工具,经历过数次的重构,在三个项目中使用。
定义一个结点类型:Node<T> 代码如下:
package com.**.power.tool.tree.node; import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.UUID; public class Node<T> implements Serializable ,Comparable{ private static final long serialVersionUID = -8658937456797684778L; private Node<T> parent; //父结点 private List<Node<T>> children; //子结点 private String id; //结点编号 private String text; //结点标签 private String parentId; //父结点编号 private int grade; //结点级别 根结点为0 private int subLevels; //结点下面最深有多少层 private boolean isexpand=false; //结点展开状态 public Node(){} public Node(T t) { this.extend=t; } // private T extend; //扩展属性 用于扩展业务属性与指定的业务实体进行扩展 //....这里省去get set方法 @SuppressWarnings("unchecked") public boolean equals(Object obj) { if (obj == null) { return false; } if (super.equals(obj)) { return true; } if (!(obj instanceof Node)) { return false; } Node<T> target = (Node<T>) obj; if (target.getId() == null) { return false; } if (target.hashCode()==hashCode()) { return true; } return false; } @Override public int compareTo(Object o) { if (o instanceof Node ) { Node tmp=(Node) o; Object ext=tmp.getExtend(); if (ext!=null&&this.getExtend()!=null) { if (ext instanceof Comparable&&this.getExtend() instanceof Comparable) { Comparable extcomp=(Comparable)this.extend; Comparable tmpcomp=(Comparable)tmp.getExtend(); int i= tmpcomp.compareTo(extcomp); System.out.println(i); return i; } } } return 0; } }
从注释上可以看出以下几点:
1.它是一个泛型类型
2.业务无关
3.有可扩展属性
4.实现了Comparable接口,从而实现对结点进行排序
这个从接口实现上可以看出,先去查看它的扩展属性是不是实现了Comparable,如果实现了就用扩展属性进行比较,如果没有实现,就不进行比较返回0,表示相等以免对结点不必要的移动。
5.它有grade级别和subLevels下面最多有多少层,以便判断是不是对该结点进行相关操作。
这篇博客到此吧,下次再说如果组装树型结构。
谢谢大家来捧场!!
欢迎留言讨论!