0

我有一个具有以下结构的数据库表:

CREATE TABLE `Professions` (
  `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
  `profession` varchar(254) NOT NULL,
  `profession_type` enum('system','custom') NOT NULL,
  PRIMARY KEY (`id`),
  KEY `profession_index` (`profession`)
) ENGINE=InnoDB AUTO_INCREMENT=296 DEFAULT CHARSET=utf8

 CREATE TABLE `Professions_Professions` (
  `parent_id` bigint(20) unsigned NOT NULL,
  `child_id` bigint(20) unsigned NOT NULL,
  PRIMARY KEY (`parent_id`,`child_id`),
  UNIQUE KEY `child_id_UNIQUE` (`child_id`),
  KEY `parent_id_index` (`parent_id`),
  CONSTRAINT `fk_Professions_Professions1` FOREIGN KEY (`parent_id`) REFERENCES `Professions` (`id`) ON DELETE CASCADE ON UPDATE CASCADE,
  CONSTRAINT `fk_Professions_Professions2` FOREIGN KEY (`child_id`) REFERENCES `Professions` (`id`) ON DELETE CASCADE ON UPDATE CASCADE
) ENGINE=InnoDB DEFAULT CHARSET=utf8

为了获得专业的整个结构,我编写了以下 SQL:

SELECT id, profession, profession_type, parent_id FROM Professions P LEFT OUTER JOIN Professions_Professions PP ON PP.child_id = P.id;

现在,我想在 Java 应用程序中表示这种类型的结构(我的位置表结构几乎相同)。
对我来说,创建某种没有根的树看起来很合理,但它是一个充当根的元素列表。每个元素都将实现“节点”接口,该接口将允许获取其父元素和子元素列表。由于这应该是通用解决方案,我希望有一个通用树。
我也想有一个程序在这棵树中上下走动并执行一些可以返回的动作(接口)(在每个孩子和每个孩子列表上 - '节点'和'节点列表'动作)某个值与否,并且可以采用任意数量的参数。
如果动作将有一个返回值,我希望它的返回类型由动作实现指定。
我试图实现这一点并最终得到以下代码(应该有很多kludges ...):

// Removed the generic because i was unable to figure out how to make it all work ... 
public interface TreeNode {
    public void setParent(Object parent);
    public void setChildList(List childList);
    public Object getParent();
    public List getChildList();
}

public class Tree<T extends TreeNode> {

    private List<T> tree;

    public Tree(List<T> treeNodeList) {
        /* Ensuse that the list is not empty */
        if((null != treeNodeList) && (!treeNodeList.isEmpty())) {
            tree = new ArrayList<T>();
            /* Link the elements and create the tree */
            for(T node:treeNodeList) {
                /* If the current node has a parent */
                if(null != node.getParent()) {
                    /* Look the actual parent object in the initial node list */
                    int parentIndex = treeNodeList.indexOf(node.getParent());
                    if(-1 != parentIndex) {
                        T parent = treeNodeList.get(parentIndex);
                        /* Set the actual parent */
                        node.setParent(parent);
                        /* Add node to parent children list */
                        if(null == parent.getChildList()) {
                            parent.setChildList(new ArrayList<T>());
                        }
                        parent.getChildList().add(node);
                    }
                }
                else {
                    /* Add element to tree root list */
                    tree.add(node);
                }
            }
        }
    }


    public List<?> getRootList() {
        return tree;
    }

    public void forEachChild(List<T> rootList, SimpleNodeTreeAction<T> action, Object... args) {
        if((null != rootList) && (!rootList.isEmpty())) {
            Object[] localArgs = null;
            for(T node:rootList) {
                /* Store the local copy of args */
                if(null != args) {
                    localArgs = args.clone();
                }
                action.doAction(node, localArgs);
                forEachChild(node.getChildList(), action, localArgs);
            }
        }
    }

    public void forEachChild(T rootNode, SimpleNodeTreeAction<T> action, Object... args) {
        if(null != rootNode) {
            forEachChild(rootNode.getChildList(), action, args);
        }
    }

    public void forEachChild(SimpleNodeTreeAction<T> action, Object... args) {
        forEachChild(tree, action, args);
    }

    public Object forEachChild(List<T> rootList, NodeTreeAction<T> action, Object... args) {
        Object result = null;
        if((null != rootList) && (!rootList.isEmpty())) {
            Object[] localArgs = null;
            for(T node:rootList) {
                /* Store the local copy of args */
                if(null != args) {
                    localArgs = args.clone();
                }
                result = action.doAction(node, localArgs);
                if(null == result) {
                    result = forEachChild(node.getChildList(), action, localArgs);
                    if(null != result) {
                        break;
                    }
                }
                else {
                    break;
                }
            }
        }
        return result;
    }

    public Object forEachChild(T rootNode, NodeTreeAction<T> action, Object... args) {
        Object result = null;
        if(null != rootNode) {
            result = forEachChild(rootNode.getChildList(), action, args);
        }
        return result;
    }

    public Object forEachChild(NodeTreeAction<T> action, Object... args) {
        return forEachChild(tree, action, args);
    }

    public void forEachChildList(List<T> rootList, SimpleNodeListTreeAction<T> action, Object... args) {
        if((null != rootList) && (!rootList.isEmpty())) {
            action.doAction(rootList, args);
            for(T node:rootList) {
                forEachChildList(node.getChildList(), action, args);
            }
        }
    }

    public void forEachChildList(T rootNode, SimpleNodeListTreeAction<T> action, Object... args) {
        if(null != rootNode) {
            forEachChildList(rootNode.getChildList(), action, args);
        }
    }

    public void forEachChildList(SimpleNodeListTreeAction<T> action, Object... args) {
        forEachChildList(tree, action, args);
    }

    public Object forEachChildList(List<T> rootList, NodeListTreeAction<T> action, Object... args) {
        Object result = null;
        if((null != rootList) && (!rootList.isEmpty())) {
            result = action.doAction(rootList, args);
            if(null == result) {
                for(T node:rootList) {
                    result = action.doAction(node.getChildList(), args);
                    if(null != result) {
                        break;
                    }
                }
            }
        }
        return result;
    }

    public Object forEachChildList(T rootNode, NodeListTreeAction<T> action, Object... args) {
        Object result = null;
        if(null != rootNode) {
            result = forEachChildList(rootNode.getChildList(), action, args);
        }
        return result;
    }

    public Object forEachChildList(NodeListTreeAction<T> action, Object... args) {
        return forEachChildList(tree, action, args);
    }

    public void forEachParent(T rootNode, SimpleNodeTreeAction<T> action, Object... args) {
        if(null != rootNode) {
            T parent = (T) rootNode.getParent();
            while(null != parent) {
                action.doAction(parent, args);
                parent = (T) parent.getParent();
            }
        }
    } 

    public Object forEachParent(T rootNode, NodeTreeAction<T> action, Object... args) {
        Object result = null;
        if(null != rootNode) {
            T parent = (T) rootNode.getParent();
            while(null != parent) {
                result = action.doAction(parent, args);
                if(null == result) {
                    parent = (T) parent.getParent();
                }
                else {
                    break;
                }
            }
        }
        return result;
    }

    public Object search(final T searchObject) {
        return forEachChild(
                new NodeTreeAction<T>() {

                    @Override
                    public Object doAction(T node, Object... args) {
                        if(node.equals(searchObject)) {
                            return node;
                        }
                        else {
                            return null;
                        }
                    }

                },
                searchObject);
    } 

    public void sort(final Comparator comparator) {
        forEachChildList(
                new SimpleNodeListTreeAction<T>() {
                    @Override
                    public void doAction(List node, Object... args) {
                        Collections.sort(node, comparator);
                    }
                }, (Object) null);
    }

    public void sort() {
        forEachChildList(
                new SimpleNodeListTreeAction<T>() {
                    @Override
                    public void doAction(List node, Object... args) {
                        Collections.sort(node);
                    }

                }, (Object) null);
    }
}

public interface NodeTreeAction<T extends TreeNode> {
    public Object doAction(T node, Object... args);
}

public interface SimpleNodeTreeAction<T extends TreeNode> {
    public void doAction(T node, Object... args);
}

public interface NodeListTreeAction<T extends TreeNode> {
    public Object doAction(List<T> node, Object... args);
}

public interface SimpleNodeListTreeAction<T extends TreeNode> {
    public void doAction(List<T> node, Object... args);
}

谁能指出我如何使这个(假设不是完美的)解决方案变得更好(例如从方法返回实际类型对象,而不是现在的对象)。如果有人能提出更好的解决方案来解决这个问题,我也将不胜感激。

提前致谢...

4

1 回答 1

0

嗯。使 Node 成为 Tree 的内部类。这使得泛型声明更简单。添加一些空检查,如果你想懒惰地创建 up 和 down 集合。

没有测试/编译这个。YMMV。

class Tree<T implements Comparable<? super T>> {
  final Collection<Node> sourceNodes = new HashSet<Node>();
  final Collection<Node> sinkNodes = new HashSet<Node>();
  final Map<T, Node<T>> allNodes = new HashMap<T, Node<T>>();

  class Node implements Comparable<Node> {
      final T t;
      final Collection<Node> up = new HashSet<Node>();
      final Collection<Node> down = new HashSet<Node>();
      Node(t) {if(t==null) throw new IllegalArgumentException(); this.t = t;}
      public int hashCode() { return t.hashCode; }
      public int equals(Node n) { return t.equals(n.t);}
      public int compareTo(Node n) { return t.compareTo(n.t);}
  }

  void makeNewNode(T t) {
    Node n = new Node(t);
    sourceNodes.add(n);
    sinkNodes(n);
    alNodes.add(t,n);
  }

  void link(T up, T down) {
    link(all.get(up), all.get(down));
  }

  void link(Node up, Node down) {
    sourceNodes.remove(down); // no need to check
    sinkNodes.remove(up); // no need to check
    up.down.add(down);
    down.up.add(up);
  }

  void unlink(T up, T down) {
    unlink(all.get(up), all.get(down));
  }

  void unlink(Node up, Node down) {
      up.down.remove(down);
      down.up.remove(up);
      if(up.down.isEmpty()) sinkNodes.add(up);
      if(down.up.isEmpty()) sourceNodes.add(down);
  }
}
于 2012-07-18T04:22:46.390 回答