আপনার গাছটি (ডোমেনের জন্য) কী তা নির্ধারণ করে শুরু করা উচিত, এটি প্রথমে ইন্টারফেসটি সংজ্ঞায়নের মাধ্যমে করা ভাল । সমস্ত গাছের কাঠামোগুলি পরিবর্তনযোগ্য নয়, নোডগুলি যুক্ত করতে এবং অপসারণ করতে সক্ষম হওয়া একটি alচ্ছিক বৈশিষ্ট্য হওয়া উচিত, তাই আমরা তার জন্য একটি অতিরিক্ত ইন্টারফেস তৈরি করি।
মানগুলি ধারণ করে এমন নোড অবজেক্ট তৈরি করার দরকার নেই , প্রকৃতপক্ষে আমি এটিকে বেশিরভাগ গাছ বাস্তবায়নের ক্ষেত্রে একটি প্রধান নকশার ত্রুটি এবং ওভারহেড হিসাবে দেখি। আপনি যদি সুইংয়ের দিকে লক্ষ্য করেন তবে TreeModel
এটি নোড ক্লাসগুলি থেকে মুক্ত (কেবলমাত্র এটি DefaultTreeModel
ব্যবহার করে TreeNode
), কারণ তাদের সত্যিকারের প্রয়োজন নেই।
public interface Tree <N extends Serializable> extends Serializable {
List<N> getRoots ();
N getParent (N node);
List<N> getChildren (N node);
}
মিউটেবল গাছের কাঠামো (নোডগুলি যুক্ত করতে এবং মুছে ফেলার অনুমতি দেয়):
public interface MutableTree <N extends Serializable> extends Tree<N> {
boolean add (N parent, N node);
boolean remove (N node, boolean cascade);
}
এই ইন্টারফেসগুলি দেওয়া, যে কোডগুলি গাছ ব্যবহার করে তাদের কীভাবে গাছটি প্রয়োগ করা হয় সে সম্পর্কে খুব বেশি যত্ন নেওয়া প্রয়োজন না। এটি আপনাকে জেনেরিক প্রয়োগ এবং সেইসাথে বিশেষায়িত জিনিসগুলি ব্যবহার করতে সহায়তা করে যেখানে আপনি অন্য API এ ফাংশনগুলি অর্পণ করে গাছটি উপলব্ধি করতে পারেন।
উদাহরণ: ফাইল গাছ কাঠামো
public class FileTree implements Tree<File> {
@Override
public List<File> getRoots() {
return Arrays.stream(File.listRoots()).collect(Collectors.toList());
}
@Override
public File getParent(File node) {
return node.getParentFile();
}
@Override
public List<File> getChildren(File node) {
if (node.isDirectory()) {
File[] children = node.listFiles();
if (children != null) {
return Arrays.stream(children).collect(Collectors.toList());
}
}
return Collections.emptyList();
}
}
উদাহরণ: জেনেরিক ট্রি স্ট্রাকচার (পিতামাতার / সন্তানের সম্পর্কের উপর ভিত্তি করে):
public class MappedTreeStructure<N extends Serializable> implements MutableTree<N> {
public static void main(String[] args) {
MutableTree<String> tree = new MappedTreeStructure<>();
tree.add("A", "B");
tree.add("A", "C");
tree.add("C", "D");
tree.add("E", "A");
System.out.println(tree);
}
private final Map<N, N> nodeParent = new HashMap<>();
private final LinkedHashSet<N> nodeList = new LinkedHashSet<>();
private void checkNotNull(N node, String parameterName) {
if (node == null)
throw new IllegalArgumentException(parameterName + " must not be null");
}
@Override
public boolean add(N parent, N node) {
checkNotNull(parent, "parent");
checkNotNull(node, "node");
// check for cycles
N current = parent;
do {
if (node.equals(current)) {
throw new IllegalArgumentException(" node must not be the same or an ancestor of the parent");
}
} while ((current = getParent(current)) != null);
boolean added = nodeList.add(node);
nodeList.add(parent);
nodeParent.put(node, parent);
return added;
}
@Override
public boolean remove(N node, boolean cascade) {
checkNotNull(node, "node");
if (!nodeList.contains(node)) {
return false;
}
if (cascade) {
for (N child : getChildren(node)) {
remove(child, true);
}
} else {
for (N child : getChildren(node)) {
nodeParent.remove(child);
}
}
nodeList.remove(node);
return true;
}
@Override
public List<N> getRoots() {
return getChildren(null);
}
@Override
public N getParent(N node) {
checkNotNull(node, "node");
return nodeParent.get(node);
}
@Override
public List<N> getChildren(N node) {
List<N> children = new LinkedList<>();
for (N n : nodeList) {
N parent = nodeParent.get(n);
if (node == null && parent == null) {
children.add(n);
} else if (node != null && parent != null && parent.equals(node)) {
children.add(n);
}
}
return children;
}
@Override
public String toString() {
StringBuilder builder = new StringBuilder();
dumpNodeStructure(builder, null, "- ");
return builder.toString();
}
private void dumpNodeStructure(StringBuilder builder, N node, String prefix) {
if (node != null) {
builder.append(prefix);
builder.append(node.toString());
builder.append('\n');
prefix = " " + prefix;
}
for (N child : getChildren(node)) {
dumpNodeStructure(builder, child, prefix);
}
}
}