2015-11-19 3 views
1

Я занят написанием API, который изменяет график. Чтобы контролировать то, что я просматриваю для пользователей API, я использую интерфейсы.Устранить необходимость в литье

Интерфейсы, раскрывающие методы, которые будут использоваться, следующие. По существу это то, что пользователь увидит:

public interface GraphEditor{ 
    Edge addEdge(AsbtractNode f, AbstractNode t) 
} 
public interface AbstractNode{ 
} 
public interface ExampleNode1 extends AbstractNode{ 
} 
public interface ExampleNode2 extends AbstractNode{ 
} 

Структура реализации:

public class GraphEditorImpl implements GraphEditor{ 
    public Edge addEdge(AsbtractNode f, AbstractNode t){ 
     AbstractNodeImpl from = (AbstractNodeImpl) f; 
     AbstractNodeImpl t = (AbstractNodeImpl) f; 
     from.getVertex().addEdge(t.getVertex); 
    } 
} 
public class AbstractNodeImpl implements AbstractNode{ 
    Vertex vertex; //Must remain hidden from users 
    public Vertex getVertex(){ 
     return vertex; 
    } 
} 

Внутри граф редактор У меня есть метод, который позволяет пользователю добавлять и ребро между двумя узлами addEdge. Этот метод должен отличать AbstractNode от AbstractNodeImpl, чтобы получить доступ к методу getVertex(), который необходим для получения «Вершины».

Я не могу разоблачить getVertex() в интерфейсе AbstractNode, так как у меня не могут быть пользователи, непосредственно работающие с Vertex. Есть ли способ достичь такого рода функциональности без необходимости отбрасывать из интерфейса в реализацию?

+5

Но так как пользователи уже имеют 'AbstractNode' объект, может 't они просто передают его в 'AbstractNodeImpl' и вызывают' getVertex() 'anyways? – AJC

+0

Что такого чувствительного к 'Vertex', что вы не хотите, чтобы пользователи имели доступ? Что мешает им обращать на него внимание или кастингать? –

+0

'AbstractNodeImpl t = (AbstractNodeImpl) f;', вероятно, опечатка ...? – Puce

ответ

3

Текущая модель не будет работать. Вы можете сделать так, что интерфейс AbstractNode содержит только информацию о себе на узле, а интерфейс GraphEditor содержит все методы должны изменить график:

interface AbstractNode { 
    // identify this node 
    // this class only contains the ID of this node 
} 

interface GraphEditor<T extends AbstractNode> { 
    // this class stores the graph 
    void addEdge(T a, T b); 
} 
+0

Бинго. Это сработало для меня. Спасибо AJC. –

1

Добавить функцию addEdge(AbstractNode) в интерфейс AbstractNode.

Реализация этой функции может быть getVertex().addEdge(that.getVertex) или что-то, что подходит для класса реализации.

И если вы не хотите, чтобы люди могли получить доступ к экземпляру Vertex, сделайте getVertex() приватным или защищенным.

+0

addEdge уже находится в интерфейсе –

+0

@Simo - это интерфейс 'GraphEditor', а не интерфейс' AbstractNode'. – anon

+0

Это не будет работать. Например: 'n1.addEdge (n2)', вы сможете напрямую обращаться к 'n1' vertex (потому что реализация добавления края будет находиться в' AbstractNodeImpl'), но вы не можете получить доступ к вершине 'n2', потому что' n2' по-прежнему является «AbstractNode», который не может получить доступ к 'getVertex'. Вам все равно придется бросать. –

0

Плохая конструкция, использующая тип в качестве параметра и отбрасывающая его под другим подтипом внутри метода.

Что происходит, если пользователь создает пользовательский класс, который расширяет AbstractNode?

Вам также необходимо учитывать, что при написании API.

Если нет другой возможности вы должны проверить в своем коде, что реальный тип параметра является AbstractNode, если вам не нужно бросать по крайней мере IllegalArgumentException

+0

Ошибка дизайна в том, что он вредит способности клиента выполнять работу в рамках данного API. Кажется очевидным, что плакат требует доступа к Vertex и как таковой должен сделать его частью интерфейса. – Constantin

+0

Таким образом, тип параметра должен быть типом, который может получить доступ к Vertex, и не требуется никакого заливки. –

Смежные вопросы