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アプリでそのタイプの構造を表現したいと思っています(場所のテーブル構造はほぼ同じです)。
ルートを持たず、ルートとして機能する要素のリストを作成するツリーを作成することは合理的に思えます。各要素は、その親と子のリストを取得できる「ノード」インターフェースを実装します。これは一般的な解決策であるため、汎用ツリーが必要です。
また、このツリーを上下に移動し、いくつかのアクション (インターフェイス) (各子および子の各リスト - 「ノード」および「ノード リスト」アクション) を実行する手順が必要です。任意の数のパラメータを取ることができます。
アクションが戻り値を持つ場合、アクションの実装で戻り値の型を指定したいと思います。
私はこれを実装しようとしましたが、最終的に次のコードになりました(多くのクラッジがあるはずです...):

// 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 コレクションを遅延して作成する場合は、null チェックを追加します。

これをテスト/コンパイルしていません。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 に答える