2016-09-01 11 views
0

Позвольте мне начать с абстрактной формулировки проблемы: у меня есть два типа открытого интерфейса. Один из них содержит метод, который получает по меньшей мере два экземпляра другого типа интерфейса. Реализация метода зависит от реализации переданных объектов.Доступ к конкретным методам реализации для объекта, возвращаемого его API

Рассмотрим следующий публичный 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 и использует downcast. Это кажется мне неправильным. Могут быть и другие варианты 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 должен быть виден клиенту, так что это все еще абсорбирующая абстракция.

+1

Я редактировал ответ с вашими новыми правками – hunter

ответ

1

Если метод подключения должен получить доступ к обернутому объекту в каждом узле, это значит, что NodeImpl может быть подключен только к NodeImpl, поэтому не нужно делать его сложным, добавить метод addChild или подключиться к интерфейсу узла, в реализации 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) 
    { 

    } 
} 
+0

я бы согласился с этим, как лучшим типом решение, но я предполагаю, что OP не имеет контроля над предоставленными интерфейсами. – Mena

+0

OP сказал, что он попытался отредактировать интерфейс узла с помощью нового метода. поэтому я думаю, что OP является автором интерфейса Node. – hunter

+0

Ах да: «Поместите метод подключения в интерфейс узла» и т. Д. Затем удалит мой и повысит ваш рейтинг. – Mena