次の構造のデータベース テーブルがあります。
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);
}
この(完璧ではない)ソリューションをより良くする方法を教えてください(たとえば、現在のオブジェクトではなく、メソッドから実際の型オブジェクトを返します)。また、誰かがこの問題のより良い解決策を提案してくれれば幸いです。
前もって感謝します...