0

問題を抽象的に定式化することから始めましょう。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マップするマップを使用してください。NodeWrappedこれは基本的に上記と同じです。インスタンスが関連付けられたマッピングを持たないメソッドにNode渡されるとすぐに壊れます。connect

Nodeインターフェイスにはメソッドが含まれる場合があることに注意してください。ただし、これはこの質問にとって重要ではありません。

また、インターフェースの宣言と実装の両方を管理していることに注意してください。


これを解決する別の試みは、メソッドをインターフェイスのメソッドに変換し、インターフェイスを汎用にすることconnectです。addChildNodeNode

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);
}

NodecreateNodeパブリック API の一部です。NodeImplそしてWrapped隠す必要があります。runクライアントコードです。ご覧のとおり、NodeImplはクライアントに表示される必要があるため、これはまだ漏れのある抽象化です。

4

1 に答える 1

1

connect メソッドが各ノードの Wrapped オブジェクトにアクセスする必要がある場合、つまり NodeImpl は NodeImpl にのみ接続できるため、複雑にする必要はありません。メソッド addChild を追加するか、Node インターフェイスに接続します。NodeImpl の実装では、型の不一致がある場合、例外をスローする可能性があります。

ダウンキャストせずにジェネリックを使用できますが、簡単な解決策はダウンキャストすることだと思います

interface NodeConnector<T extends Node>
{
  void  connect(T parent,T child);
}


public abstract class AbstractNode implements Node
{
  @Override
  public void connect(Node node)
  {

    NodeConnector<Node> nodeConnector = getNodeConnector();
    nodeConnector.connect(this, node);
    Node parent = this;
  }

  protected abstract NodeConnector<Node> getNodeConnector();


}

class NodeImpl extends AbstractNode
{
  @SuppressWarnings("unchecked")
  protected NodeConnector<Node> getNodeConnector()
  {
    return (NodeConnector) new NodeConnectorImpl();
  }
}



class NodeConnectorImpl implements NodeConnector<NodeImpl>
{
  @Override
  public void connect(NodeImpl parent, NodeImpl child)
  {

  }
}
于 2016-09-01T10:25:47.083 に答える