0

让我从抽象地表述问题开始:我有两种公共接口类型。其中一个包含一个方法,该方法至少接收另一个接口类型的两个实例。方法的实现取决于传递的对象的实现。

考虑以下公共 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
}

我需要访问connect方法中的包装对象,这是不可能的,因为该getWrapped方法不是 API 的一部分。这是一个实现细节。

所以问题是:如何在connect不向 API 泄​​露实现细节的情况下实现该方法?

这是我到目前为止所尝试的:

  • connect方法放入Node接口并调用parent.connect(child). 这使我可以访问父对象的包装对象,但是子对象的包装对象仍然不可用。

  • 只需假设传递Node的是类型NodeImpl并使用向下转换。这对我来说似乎是错误的。可能还有其他Node实现。

  • 不要将包装的对象放在节点中,而是使用映射到对象的TreeImpl映射。NodeWrapped这与上面的基本相同。一旦将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必须对客户端可见,因此这仍然是一个泄漏的抽象。

4

1 回答 1

1

如果 connect 方法需要访问每个节点中的 Wrapped 对象,也就是说 NodeImpl 只能连接到一个 NodeImpl,所以不需要复杂,添加方法 addChild 或连接到 Node 接口,在 NodeImpl 实现中可以向下转换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 回答