問題を抽象的に定式化することから始めましょう。2 つのパブリック インターフェイス タイプがあります。それらの 1 つには、他のインターフェイス タイプのインスタンスを少なくとも 2 つ受け取るメソッドが含まれています。メソッドの実装は、渡されたオブジェクトの実装に依存します。
2 つのインターフェイスで構成される次のパブリック API について考えてみましょう。
public interface Node {
}
public interface Tree {
void connect(Node parent, Node child);
}
次に、その API を次のように実装します。
public class NodeImpl implements Node {
private final Wrapped wrapped;
public NodeImpl(Wrapped wrapped) {
this.wrapped = wrapped;
}
public Wrapped getWrapped() {
return wrapped;
}
}
public class TreeImpl implements Tree {
@Override
public void connect(Node parent, Node child) {
// connect parent and child using the wrapped object
}
}
public class Wrapped {
// wrapped object which actually represents the node internally
}
メソッド内のラップされたオブジェクトにアクセスする必要がありますが、メソッドは API の一部ではないconnect
ため、これは不可能です。getWrapped
実装の詳細です。
connect
問題は、実装の詳細を API に漏らさずにメソッドを実装するにはどうすればよいかということです。
これが私がこれまでに試したことです:
connect
メソッドをNode
インターフェースに入れ、 を呼び出しますparent.connect(child)
。これにより、親のラップされたオブジェクトにアクセスできるようになりますが、子のラップされたオブジェクトはまだ利用できません。渡された
Node
のが型であると仮定してNodeImpl
、ダウンキャストを使用してください。これは私には間違っているようです。他のNode
実装があるかもしれません。ラップされたオブジェクトをノードに配置しないでください。をオブジェクトに
TreeImpl
マップするマップを使用してください。Node
Wrapped
これは基本的に上記と同じです。インスタンスが関連付けられたマッピングを持たないメソッドにNode
渡されるとすぐに壊れます。connect
Node
インターフェイスにはメソッドが含まれる場合があることに注意してください。ただし、これはこの質問にとって重要ではありません。
また、インターフェースの宣言と実装の両方を管理していることに注意してください。
これを解決する別の試みは、メソッドをインターフェイスのメソッドに変換し、インターフェイスを汎用にすることconnect
です。addChild
Node
Node
public interface Node<T extends Node<T>> {
void addChild(Node<T> child);
}
public class NodeImpl implements Node<NodeImpl> {
private final Wrapped wrapped;
public NodeImpl(Wrapped wrapped) {
this.wrapped = wrapped;
}
public Wrapped getWrapped() {
return wrapped;
}
@Override
public void addChild(Node<NodeImpl> child) {
}
}
public class Wrapped {
// wrapped object which actually represents the node internally
}
public Node<NodeImpl> createNode() {
return new NodeImpl(new Wrapped());
}
private void run() {
Node<NodeImpl> parent = createNode();
Node<NodeImpl> child = createNode();
parent.addChild(child);
}
Node
createNode
パブリック API の一部です。NodeImpl
そしてWrapped
隠す必要があります。run
クライアントコードです。ご覧のとおり、NodeImpl
はクライアントに表示される必要があるため、これはまだ漏れのある抽象化です。