使用樹形結(jié)構(gòu)保存實體

tree

閱讀原文請訪問我的博客BrightLoong's Blog

之前在項目需要實現(xiàn)一個功能——將xml文件映射成實體,然后對映射的實體進行邏輯處理,最后保存到數(shù)據(jù)庫中;由于xml結(jié)構(gòu)的數(shù)據(jù)是結(jié)構(gòu)化的數(shù)據(jù),所以需要保證保存的數(shù)據(jù)具有正確的主外鍵關(guān)聯(lián)。如下所示,是一個需要保存到數(shù)據(jù)庫的xml文件。當(dāng)映射成對應(yīng)的實體school和student的時候,我們需要知道“school-one”下面有哪些學(xué)生,“school-two”下面有哪些學(xué)生,這個時候想到了使用樹形結(jié)構(gòu)來保存實體,讓實體之間依然存在關(guān)聯(lián)關(guān)系。

<school-inf>
  <msg>2017-10-1XX省學(xué)校信息總匯</msg>
  <schools>
    <school>
      <name>school-one</name>
      <students>
        <student>Jack</student>
        <student>Rose</student>
        <student>Jon</student>
      </students>
    </school>
    <school>
      <name>school-two</name>
      <students>
        <student>Bob</student>
        <student>Alisa</student>
        </students>
      </school>
    </schools>
</school-inf>

樹形工具

以下是樹形工具類的實現(xiàn),包含了樹形節(jié)點類和樹形結(jié)構(gòu)類,由于代碼中注釋已經(jīng)比較全面,所以不做過多的說明。

樹形節(jié)點類BeanTreeNode.java

每一個節(jié)點對應(yīng)一個實體,節(jié)點包含了實體信息,為了保證實體之間的關(guān)聯(lián)關(guān)系,需要留有父節(jié)點信息,所有的子節(jié)點信息。由此推斷出,節(jié)點的主要成員有

  • 父節(jié)點信息
  • 所有子節(jié)點信息
  • 當(dāng)前實體信息

為了方便操作,我還多增加了id和pid(parent id),以及節(jié)點類型(nodeType)。對id的相關(guān)操作我并沒有添加,如果需要可以自行添加。

import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * 實體樹形結(jié)構(gòu)點
 * BeanTreeNode
 * @author BrightLoong
 * @version 1.0
 *
 */
public class BeanTreeNode {
    
    /**標識id*/
    private String id;
    
    /**父id標識,為了方便獲取冗余出來*/
    private String pid;
    
    /**父節(jié)點*/
    private BeanTreeNode parentNode;
    
    /**節(jié)點類型*/
    private String nodeType;
    
    /**節(jié)點值*/
    private Object bean;
    
    /**子節(jié)點*/
    private List<BeanTreeNode> childNodes;
    

    /**
     * @param parentNode
     * @param nodeType
     * @param bean
     * @param childNodes
     */
    public BeanTreeNode(BeanTreeNode parentNode, String nodeType, Object bean) {
        this.parentNode = parentNode;
        this.nodeType = nodeType;
        this.bean = bean;
        this.childNodes = new ArrayList<BeanTreeNode>();
        this.id = UUID.randomUUID().toString().replaceAll("-", "");
        if (parentNode != null) {
            this.pid = parentNode.getId();
        }
    }

    /**
     * @return the nodeType
     */
    public String getNodeType() {
        return nodeType;
    }

    /**
     * @param nodeType the nodeType to set
     */
    public void setNodeType(String nodeType) {
        this.nodeType = nodeType;
    }

    /**
     * @return the parentNode
     */
    public BeanTreeNode getParentNode() {
        return parentNode;
    }

    /**
     * @param parentNode the parentNode to set
     */
    public void setParentNode(BeanTreeNode parentNode) {
        this.parentNode = parentNode;
    }

    /**
     * @return the bean
     */
    public Object getBean() {
        return bean;
    }

    /**
     * @param bean the bean to set
     */
    public void setBean(Object bean) {
        this.bean = bean;
    }

    /**
     * @return the childNodes
     */
    public List<BeanTreeNode> getChildNodes() {
        return childNodes;
    }

    /**
     * @param childNodes the childNodes to set
     */
    public void setChildNodes(List<BeanTreeNode> childNodes) {
        this.childNodes = childNodes;
    }

    /**
     * @return the id
     */
    public String getId() {
        return id;
    }

    /**
     * @param id the id to set
     */
    public void setId(String id) {
        this.id = id;
    }

    /**
     * @return the pid
     */
    public String getPid() {
        return pid;
    }

    /**
     * @param pid the pid to set
     */
    public void setPid(String pid) {
        this.pid = pid;
    }
    
    /**
     * 是否具有子節(jié)點
     * @return true or false
     */
    public boolean haveChild() {
        return !CollectionUtils.isEmpty(childNodes);
    }
}

樹形結(jié)構(gòu)類BeanTree.java

BeanTree.java里面包含了如下的一些常用操作:

  • 返回根節(jié)點
  • 返回最后添加節(jié)點
  • 判斷是否具有子節(jié)點
  • 添加節(jié)點
  • 移動節(jié)點到其他節(jié)點下
  • 獲取對應(yīng)nodeType的所有節(jié)點或?qū)嶓w
  • 根據(jù)實體獲取節(jié)點
  • 獲取父節(jié)點
  • 轉(zhuǎn)化為map結(jié)構(gòu)

代碼如下

import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.collections.CollectionUtils;

/**
 * 實體樹形結(jié)構(gòu)
 * BeanTree
 * @author BrightLoong
 * @version 1.0
 *
 */
public class BeanTree {
    /**根節(jié)點*/
    private BeanTreeNode root;
    
    /**
     * 最新添加的節(jié)點
     */
    private BeanTreeNode currentNode;
    
    
    /**
     * @return the currentNode
     */
    public BeanTreeNode getCurrentNode() {
        return currentNode;
    }

    /**
     * @return the root
     */
    public BeanTreeNode getRoot() {
        return root;
    }
    
    /**
     * 判斷節(jié)點是否有子節(jié)點.
     * @param node 要判斷的節(jié)點
     * @return true or false
     */
    public boolean haveChild(BeanTreeNode node) {
        return CollectionUtils.isEmpty(node.getChildNodes());
    }
    
    /**
     * 在父節(jié)點上面添加節(jié)點,并返回天添加的節(jié)點.
     * @param parentNode 父節(jié)點
     * @param bean 要添加的bean
     * @param nodeType 節(jié)點類型
     * @return 返回包含bean的節(jié)點
     */
    public BeanTreeNode addNode(BeanTreeNode parentNode, Object bean, String nodeType) {
        BeanTreeNode node;
        if (bean == null) {
            return null;
        }
        //如果沒有父節(jié)點說明為root根節(jié)點
        if (parentNode == null) {
            node = root = new BeanTreeNode(null, nodeType, bean);
        } else {
            //創(chuàng)建子節(jié)點,并添加到父節(jié)點上
            node = new BeanTreeNode(parentNode, nodeType, bean);
            parentNode.getChildNodes().add(node);
        }
        currentNode = node;
        return node;
    }
    
    /**
     * 將當(dāng)期bean-sBean,以及sBean下的子Bean,掛到dBean下
     * @param sBean 源Bean
     * @param dBean 目的父Bean
     */
    public void removeTo(Object sBean, Object dBean) {
        BeanTreeNode sNode = getNodeByBean(sBean);
        BeanTreeNode dNode = getNodeByBean(dBean);
        removeTo(sNode, dNode);
    }
    
    /**
     * 將當(dāng)期node-sNode,以及sNode下的子Node,掛到dNode下
     * @param sNode 源node
     * @param dNode 目的父node
     */
    public void removeTo(BeanTreeNode sNode, BeanTreeNode dNode) {
        //從當(dāng)前父節(jié)點移除sNode
        sNode.getParentNode().getChildNodes().remove(sNode);
        //將sNode移到dNode下
        dNode.getChildNodes().add(sNode);
        //修改sNode的父Id和父節(jié)點
        sNode.setPid(dNode.getId());
        sNode.setParentNode(dNode);
    }
    
    /**
     * 獲取父bean.
     * @param bean 子bean
     * @return 返回父bean
     */
    public Object getParentBean(Object bean) {
        return getNodeByBean(bean).getParentNode().getBean();
    }
    
    /**
     * 根據(jù)傳入的bean獲取bean下面對應(yīng)類型的子bean.
     * @param bean 當(dāng)前bean
     * @param nodeType 節(jié)點類型
     * @return 子bean的集合
     */
    public List<Object> getBeanListByBeanAndNodeType(Object bean, String nodeType) {
        BeanTreeNode node = getNodeByBean(bean);
        return getBeanListByNodeType(node, nodeType);
    }
    
    /**
     * 根據(jù)傳入的bean獲取包含bean的Node節(jié)點
     * @param node 當(dāng)前node
     * @param bean 要查找的bean
     * @return node節(jié)點
     */
    public BeanTreeNode getNodeByBean(BeanTreeNode node, Object bean) {
        BeanTreeNode resultNode = null;
        if (node.getBean().equals(bean)) {
            resultNode = node;
            return resultNode;
        } else {
            for (BeanTreeNode tempNode : node.getChildNodes()) {
                resultNode = getNodeByBean(tempNode, bean);
                if (resultNode != null) {
                    break;
                }
            }
        }
        return resultNode;
    }
    
    /**
     * 根據(jù)傳入的bean獲取root節(jié)點下包含bean的Node節(jié)點
     * @param bean 要查找的bean
     * @return node節(jié)點
     */
    public BeanTreeNode getNodeByBean(Object bean) {
        return getNodeByBean(root, bean);
    }
    
    /**
     * 根據(jù)節(jié)點類型返回當(dāng)前節(jié)點下對應(yīng)節(jié)點類型的bean的list集合.
     * 默認如果當(dāng)前節(jié)點滿足類型,那么當(dāng)前節(jié)點不會存在相同類型的子節(jié)點
     * @param node 當(dāng)前節(jié)點
     * @param nodeType 節(jié)點類型
     * @return
     */
    @SuppressWarnings("unchecked")
    public <T> List<T> getBeanListByNodeType(BeanTreeNode node, String nodeType) {
        List<T> beanList = new ArrayList<T>();
        if (node.getNodeType().equals(nodeType)) {
            beanList.add((T)node.getBean());
        } else {
            for (BeanTreeNode tempNode : node.getChildNodes()) {
                beanList.addAll((Collection<? extends T>) getBeanListByNodeType(tempNode, nodeType));
            }
        }
        return beanList;
    }
    /**
     * 根據(jù)節(jié)點類型返回根節(jié)點下對應(yīng)節(jié)點類型的bean的list集合.
     * @param nodeType 節(jié)點類型
     * @return
     */
    public <T> List<T> getBeanListByNodeType(String nodeType) {
        return getBeanListByNodeType(root, nodeType);
    }
    
    /**
     * 從root節(jié)點開始獲取對應(yīng)nodeType的node.
     * @param nodeType 節(jié)點類型
     * @return nodeType類型的節(jié)點集合
     */
    public List<BeanTreeNode> getNodeListByNodeType(String nodeType) {
        return getNodeListByNodeType(root, nodeType);
    }
    
    /**
     * 從node節(jié)點開始獲取對應(yīng)nodeType的node.
     * @param node node節(jié)點
     * @param nodeType 節(jié)點類型
     * @return nodeType類型的節(jié)點集合
     */
    public List<BeanTreeNode> getNodeListByNodeType(BeanTreeNode node, String nodeType) {
        List<BeanTreeNode> nodeList = new ArrayList<BeanTreeNode>();
        if(node==null){
            return nodeList;  
        }
        if (nodeType.equals(node.getNodeType())) {
            nodeList.add(node);
        } else {
            for (BeanTreeNode tempNode : node.getChildNodes()) {
                nodeList.addAll(getNodeListByNodeType(tempNode, nodeType));  
            }
        }
        
        return nodeList;
    }
    
    /**
     * 將樹形結(jié)構(gòu)轉(zhuǎn)化為map.
     * @return
     */
    public Map<String, List<Object>> toMap() {
        return toMap(root);
    }
    
    /**
     * 將對應(yīng)節(jié)點及其子節(jié)點轉(zhuǎn)化為map.
     * @param node 樹節(jié)點
     * @return 轉(zhuǎn)化后的map
     */
    public Map<String, List<Object>> toMap(BeanTreeNode node) {
        Map<String, List<Object>> map = new HashMap<String, List<Object>>();
        toMap(node, map);
        return map;
    }
    
    
    /**
     * 根據(jù)傳入的nodeType刪除對應(yīng)的節(jié)點以及其所有子節(jié)點.
     * @param nodeType
     */
    public void delNodeByNodeType(String nodeType) {
        delNodeByNodeType(root, nodeType);
    }
    
    /**
     * 刪除node節(jié)點下,類型為nodeType的節(jié)點和所有子節(jié)點
     * @param node
     * @param nodeType
     */
    public void delNodeByNodeType(BeanTreeNode node, String nodeType) {
        List<BeanTreeNode> nodeList = getNodeListByNodeType(node, nodeType);
        for (BeanTreeNode beanTreeNode : nodeList) {
            beanTreeNode.getParentNode().getChildNodes().remove(beanTreeNode);
        }
    }
    
    /**
     * 從樹結(jié)構(gòu)里面刪除bean和相關(guān)node.
     * @param bean bean
     */
    public void delNodeByBean(Object bean) {
        BeanTreeNode node = getNodeByBean(bean);
        BeanTreeNode parentNode = node.getParentNode();
        List<BeanTreeNode> childNodes = parentNode.getChildNodes();
        Iterator<BeanTreeNode> it = childNodes.iterator();
        while (it.hasNext()) {
            BeanTreeNode beanTreeNode = it.next();
            if (node == beanTreeNode) {
                it.remove();
            }
        }
    }
    
    
    /**
     * 根據(jù)class返回對應(yīng)的beanList.
     * @param cls class
     * @return beanList
     */
    public <T> List<Object> getBeanListByClass(Class<T> cls) {
        return getBeanListByClass(root, cls);
    }
    
    /**
     * 根據(jù)class返回對應(yīng)的beanList.
     * @param node 節(jié)點
     * @param cls class
     * @return beanList
     */
    public <T> List<Object> getBeanListByClass(BeanTreeNode node, Class<T> cls) {
        List<Object> beanList = new ArrayList<Object>();
        Object bean = node.getBean();
        if (cls.isAssignableFrom(bean.getClass())) {
            beanList.add(bean);
        }
        List<BeanTreeNode> childNodes = node.getChildNodes();
        for (BeanTreeNode beanTreeNode : childNodes) {
            beanList.addAll(getBeanListByClass(beanTreeNode, cls));
        }
        return beanList;
    }
    
    
    /**
     * 將對應(yīng)節(jié)點及其子節(jié)點轉(zhuǎn)化為map.
     * @param node 樹節(jié)點
     * @param map 用來保存結(jié)果的map
     */
    private void toMap(BeanTreeNode node, Map<String, List<Object>> map) {
        String key = node.getNodeType();
        Object bean = node.getBean();
        if (map.containsKey(key)) {
            map.get(key).add(bean);
        } else {
            List<Object> list = new ArrayList<Object>();
            list.add(bean);
            map.put(key, list);
        }
        for (BeanTreeNode tempNode : node.getChildNodes()) {
            toMap(tempNode, map);
        }
    }
}

測試樹形工具

使用上面的xml進行測試,這里就不再做xml映射,假設(shè)存在上面xml所示的所有實體,“school-one”和“school-two”以及5個student,看看能否構(gòu)造出想要的結(jié)構(gòu),測試類代碼如下。

class SchoolInf {
    private String msg;
    public SchoolInf(String msg) {
        this.msg = msg;
    }
}

class Student {
    private String name;
    public Student(String name) {
        this.name = name;
    }
}

class School {
    private String name;
    public School(String name) {
        this.name = name;
    }
}

public class Test {
    public static void main(String[] args) {
        SchoolInf schoolInf = new SchoolInf("2017-10-1XX省學(xué)校信息總匯");
        School school_one = new School("school-one");
        School school_two = new School("school-two");
        Student Jack = new Student("Jack");
        Student Rose = new Student("Rose");
        Student Jon = new Student("Jon");
        Student Bob = new Student("Bob");
        Student Alisa = new Student("Alisa");
        
        BeanTree tree = new BeanTree();
        BeanTreeNode root = tree.addNode(null, schoolInf, "root");
        BeanTreeNode school_node1 = tree.addNode(root, school_one, "school");
        BeanTreeNode school_node2 = tree.addNode(root, school_two, "school");
        tree.addNode(school_node1, Jack, "root");
        tree.addNode(school_node1, Rose, "root");
        tree.addNode(school_node1, Jon, "root");
        tree.addNode(school_node2, Bob, "root");
        tree.addNode(school_node2, Alisa, "root");
        
        System.out.println("end");
    }
}

我們通過調(diào)試觀察樹結(jié)構(gòu)變量“tree”的值如下:

result

可以看出來能夠構(gòu)造出正確的結(jié)構(gòu),BeanTree中其他的一些方法這里就不在一一測試了。

更新記錄

  • 2018/1/10,在BeanTree中添加更多的操作方法。
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn),斷路器,智...
    卡卡羅2017閱讀 136,694評論 19 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 179,323評論 25 708
  • 去過的地方不是很多,但從我有限的旅行經(jīng)歷里,越南談不上是讓人驚艷的目的地,可是它很舒服,用英文說就是很cozy。這...
    牙牙蘿卜一枝花閱讀 343評論 0 1
  • 前幾天看到一篇文章中一句話直戳人心,說的是世間除了你的父母愛人,真正希望你過得好的人沒有幾個。當(dāng)時看到這個...
    土土它它閱讀 171評論 0 0
  • “忍受那不能忍受的苦難,跋涉那不能跋涉的泥濘,負擔(dān)那負擔(dān)不了的重擔(dān),探索那探索不及的星空。”塞萬提斯如此深刻...
    欣的微風(fēng)閱讀 284評論 0 0

友情鏈接更多精彩內(nèi)容