對(duì)于java的樹形結(jié)構(gòu)的抽象與拓展
近來幾日,在學(xué)習(xí)hibernate,在做練習(xí)的時(shí)候,想做一個(gè)樹形結(jié)構(gòu)出來,比如組織架構(gòu),于是開始動(dòng)手去嘗試,首先是利用hibernate自己的方式做一棵樹,于是開始動(dòng)手構(gòu)建persisten object,代碼如下:
- package com.zq.po;
- import javax.persistence.*;
- import java.util.List;
- @Entity
- @Table(name = "t_modual")
- public class Modual2 {
- private long dbid;
- private String nane;
- private String url;
- private Modual2 parent;
- private List<Modual2> children;
- public Modual2() {
- }
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- public long getDbid() {
- return dbid;
- }
- public void setDbid(long dbid) {
- this.dbid = dbid;
- }
- public String getNane() {
- return nane;
- }
- public void setNane(String nane) {
- this.nane = nane;
- }
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- @ManyToOne
- @JoinColumn(name = "parent_id")
- public Modual2 getParent() {
- return parent;
- }
- public void setParent(Modual2 parent) {
- this.parent = parent;
- }
- @OneToMany(mappedBy = "parent",cascade = CascadeType.ALL,fetch = FetchType.EAGER)
- public List<Modual2> getChildren() {
- return children;
- }
- public void setChildren(List<Modual2> children) {
- this.children = children;
- }
- }
然后利用代碼聲生成結(jié)構(gòu),但是這樣一來,生成的表中,parent_id是強(qiáng)制關(guān)聯(lián)自己表的主鍵的,感覺這樣不是很靈活,于是就想著,把外鍵約束去掉,轉(zhuǎn)而在程序里控制好,這樣靈活性提高了。想想在工作中遇到的樹形結(jié)構(gòu)的表設(shè)計(jì)中,也沒有加入外鍵約束,所以我就開始構(gòu)建一個(gè)沒有外鍵約束的樹形結(jié)構(gòu)。
經(jīng)過思考,我決定使用如下的方式實(shí)現(xiàn):抽象出一個(gè)BaseTree來,里面有主鍵,父親節(jié)點(diǎn)的ID,父親節(jié)點(diǎn)的對(duì)象和兒子節(jié)點(diǎn)的集合,這基本上是所有樹形結(jié)構(gòu)都共有的特性,所以抽象出來,讓其他的樹去繼承,然后讓程序員更加關(guān)注本樹的業(yè)務(wù)字段。抽象出來的BaseTree代碼如下:
- package com.zq.po;
- import java.util.List;
- public class BaseTree<T> {
- private long dbid;
- private long parentId;
- private T parent;
- private List<T> children;
- public long getDbid() {
- return dbid;
- }
- public void setDbid(long dbid) {
- this.dbid = dbid;
- }
- public long getParentId() {
- return parentId;
- }
- public void setParentId(long parentId) {
- this.parentId = parentId;
- }
- public T getParent() {
- return parent;
- }
- public void setParent(T parent) {
- this.parent = parent;
- }
- public List<T> getChildren() {
- return children;
- }
- public void setChildren(List<T> children) {
- this.children = children;
- }
- }
然后再創(chuàng)建一棵樹,讓他繼承BaseTree,但是需要重寫主鍵和父節(jié)點(diǎn)ID這兩個(gè)屬性,因?yàn)樾枰阉麄冇成涞綌?shù)據(jù)庫里面去,代碼如下:
- package com.zq.po;
- import javax.persistence.*;
- import java.util.List;
- @Entity
- @Table(name="t_orga")
- public class Organization extends BaseTree<Organization>{
- private long dbid;
- private long parentId;
- private String name;
- private int count;
- //private Organization parent;
- //private List<Organization> children;
- public Organization() {
- }
- @Id
- @GeneratedValue(strategy = GenerationType.IDENTITY)
- public long getDbid() {
- return dbid;
- }
- public void setDbid(long dbid) {
- this.dbid = dbid;
- }
- public String getName() {
- return name;
- }
- public void setName(String name) {
- this.name = name;
- }
- public int getCount() {
- return count;
- }
- public void setCount(int count) {
- this.count = count;
- }
- public long getParentId() {
- return parentId;
- }
- public void setParentId(long parentId) {
- this.parentId = parentId;
- }
- /*@Transient
- public Organization getParent() {
- return parent;
- }
- public void setParent(Organization parent) {
- this.parent = parent;
- }
- @Transient
- public List<Organization> getChildren() {
- return children;
- }
- public void setChildren(List<Organization> children) {
- this.children = children;
- }*/
- }
這樣,模型就出來了,創(chuàng)建出來的表結(jié)構(gòu)如下圖:完全沒有了外鍵約束符合要求:
雖然是模型和表都整出來了,但是有一個(gè)問題,當(dāng)我們把所有的樹節(jié)點(diǎn)都查詢出來的時(shí)候,他們自身只有一個(gè)父節(jié)點(diǎn)的ID,想訪問他的父節(jié)點(diǎn)或者是孩子節(jié)點(diǎn),需要拿著該節(jié)點(diǎn)的主鍵查孩子節(jié)點(diǎn)或者拿著patentId查父親節(jié)點(diǎn),很是麻煩,于是就想著整一個(gè)工具類,把全查出來的節(jié)點(diǎn)的父親和兒子都匹配上,目前只是完成了全部節(jié)點(diǎn)的匹配,以后還會(huì)完成某一個(gè)節(jié)點(diǎn)的匹配。建了一個(gè)工具類,代碼如下:
- public class BaseTreeUtil extends BaseTree {
- private BaseTree baseTree1;
- private BaseTree baseTree2;
- public List allInit(List param) {
- //找老子
- for (int i = 0; i < param.size(); i++) {
- baseTree1 = (BaseTree) param.get(i);
- if (baseTree1.getParentId() == -1) {
- break;
- } else {
- for (int j = 0; j < param.size(); j++) {
- baseTree2 = (BaseTree) param.get(j);
- if (baseTree2.getDbid() == baseTree1.getParentId()) {
- baseTree2.setParent(baseTree1);
- }
- }
- }
- }
- //找兒子
- for (int k = 0; k < param.size(); k++) {
- baseTree1 = (BaseTree) param.get(k);
- List<BaseTree> sons = new ArrayList<BaseTree>();
- for (int l = 0; l < param.size(); l++) {
- baseTree2 = (BaseTree) param.get(l);
- if (baseTree1.getDbid() == baseTree2.getParentId()) {
- sons.add(baseTree2);
- }
- }
- baseTree1.setChildren(sons);
- }
- return param;
- }
- }
這樣就是把查出來的節(jié)點(diǎn)做循環(huán),先是給每個(gè)節(jié)點(diǎn)的找到父親節(jié)點(diǎn),然后在給每個(gè)節(jié)點(diǎn)去找兒子節(jié)點(diǎn)。
附上一段測(cè)試代碼(片段):
- public static void print(Organization orga, int level) {
- String show = "";
- for (int i = 0; i < level; i++) {
- show += "----";
- }
- System.out.println(show + orga.getName());
- level++;
- for (Organization children : orga.getChildren()) {
- print(children, level);
- }
- }
- @Test
- public void testSelect02() {
- Session session = this.before();
- Transaction tx = session.beginTransaction();
- Query query =session.createQuery("from Organization ");
- List<Organization> list=query.list();
- List list2= new BaseTreeUtil().allInit(list);
- print((Organization)list2.get(0), 0);
- this.after(tx);
- }
不好意思,忘記附上表的數(shù)據(jù)了,補(bǔ)上:
最后測(cè)試的結(jié)果如下:
到此,基本的功能都已經(jīng)實(shí)現(xiàn)了,剩下需要做的有如下幾個(gè):
1、晚上BaseTreeUtil的功能
2、把以上內(nèi)容應(yīng)用到DAO層的編寫中,整合到spring進(jìn)行測(cè)試
后續(xù)工作的總結(jié)寫在下次日志中。
原文鏈接:http://www.software8.co/wzjs/java/3335.html
posted on 2013-03-13 17:33 你爸是李剛 閱讀(1925) 評(píng)論(0) 編輯 收藏