私がやっていることは簡単ではありません。私はそれを認識します。しかし、私は私が調理したものがより良い方法があると思います。問題は次のとおりです。評価可能なノードを格納するツリーをレンダリングするためのジェネリッククラスを作成しようとしています。たとえば、ノードが値を格納していて、その値に評価している、またはランダムな値を生成している、他の多くのノード上での操作です - したがって、私はツリーと言いますが、真実はノードの内部状態が不明であることです(例えば、NodeはChildrenのNodeフィールドを0,1,2以上持つかもしれません)。子のArrayListなど)。もちろん、各ノードがレンダリングする方法を知っていれば、これは問題ではありませんが、私はこれを避けようとしています。 (理想的には、レンダーを変更するだけで、ツリーを文字列やOpenGLグラフィックなどにレンダリングすることができます。ああ、「何が良いの?」といった質問はしないでください。面白いように私はこれをやっているから。未知のノードのツリーのレンダリングを一般化する
(私は、少なくともノードに彼らがレンダリングできるという知識、およびレンダリングの論理構造を決定する能力を与えることができるが、これはおそらく、このあまり改善されないだろうと考え出し今では)これは私がこれまで持っているものです。 ノード
public interface Node<T> {
T evaluate();
}
値ノードのクラスのためのインタフェース:
public class ValueNode<T> implements Node<T> {
private T value;
@Override
public T evaluate() {
return value;
}
public ValueNode(T value) {
this.value = value;
}
}
A GEN二項演算子のためのERALクラス:
public abstract class BinaryOperator<A, B, T> implements Node<T> {
private Node<A> left;
private Node<B> right;
public BinaryOperator(Node<A> left, Node<B> right) {
this.left = left;
this.right = right;
}
public Node<A> getLeft() {
return left;
}
public Node<B> getRight() {
return right;
}
}
整数加算のためのクラス:
/**
* I couldn't figure out a generic way to add 2 numbers,
* so I'm going with just Integer for now.
*
*/
public class IntegerAdditionNode extends BinaryOperator<Integer, Integer, Integer> {
public IntegerAdditionNode (Node<Integer> left, Node<Integer> right) {
super(left,right);
}
public Integer evaluate() {
return getLeft().evaluate() + getRight().evaluate();
}
}
そして最後に、新しいレンダリングオプションが可能になります例文字列レンダラークラスを動的に追加します。これは、しかし、非常に醜いだ、と私は考えか、私はこの1つはより良い行うことができますどのように右方向にだけ光のプッシュを本当に感謝:
import java.util.HashMap;
public class NodeToString {
public interface RenderMethod {
public <T extends Node<?>> String renderNode(T node);
}
public static void main(String[] args) {
//test
NodeToString renderer = new NodeToString();
RenderMethod addRender = new RenderMethod() {
private NodeToString render;
public RenderMethod addNodeToString(NodeToString render) {
this.render = render;
return this;
}
@Override
public <T extends Node<?>> String renderNode(T node) {
IntegerAdditionNode addNode = (IntegerAdditionNode) node;
return render.render(addNode.getLeft()) +"+"+render.render(addNode.getRight());
}
}.addNodeToString(renderer);
renderer.addRenderMethod(IntegerAdditionNode.class, addRender);
RenderMethod valueRender = new RenderMethod() {
@Override
public <T extends Node<?>> String renderNode(T node) {
return ((ValueNode<?>)node).evaluate().toString();
}
};
//I don't know why I have to cast here. But it doesn't compile
//if I don't.
renderer.addRenderMethod((Class<? extends Node<?>>) ValueNode.class,
valueRender);
Node<Integer> node = new IntegerAdditionNode(new ValueNode<Integer>(2),
new ValueNode<Integer>(3));
System.out.println(renderer.render(node));
}
private HashMap<Class<? extends Node<?>>, RenderMethod> renderMethods = new
HashMap<Class<? extends Node<?>>, NodeToString.RenderMethod>();
/**
* Renders a Node
* @param node
* @return
*/
public <T extends Node<?>> String render(T node) {
Class nodeType = node.getClass();
if(renderMethods.containsKey(nodeType)) {
return renderMethods.get(nodeType).renderNode(node);
} else {
throw new RuntimeException("Unknown Node Type");
}
}
/**
* This adds a rendering Method for a specific Node type to the Renderer
* @param nodeType
* @param method
*/
public void addRenderMethod(Class<? extends Node<?>> nodeType, RenderMethod method) {
renderMethods.put(nodeType, method);
}
}
ビジターパターンを試していない理由:これは、それほど複雑な私のために少なくともなりますか? –
それはうまくいかないでしょう - 新しいNode型を追加するたびに、私はビジターインターフェイスを変更する必要があります。ビジターは、データ構造を変更することなく操作を追加したい場合は素晴らしいですが、私の場合、新しい種類のデータ(この場合は新しいノード)を追加し、新しい操作(追加のレンダリング方法)を追加できるようにしたいと考えています。正直なところ、これを行う良い方法があるのかどうか分からない。 – Cubic
何かに関係なくレンダラーを追加する必要があります。 –