Позвольте мне начать с абстрактной формулировки проблемы: у меня есть два типа открытого интерфейса. Один из них содержит метод, который получает по меньшей мере два экземпляра другого типа интерфейса. Реализация метода зависит от реализации переданных объектов.Доступ к конкретным методам реализации для объекта, возвращаемого его 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
должен быть виден клиенту, так что это все еще абсорбирующая абстракция.
Я редактировал ответ с вашими новыми правками – hunter