Как лучше всего работать со многими интерфейсами?

У меня есть ситуация, когда у меня есть много классов моделей (~ 1000), которые реализуют любое количество из 5 интерфейсов. Итак, у меня есть классы, которые реализуют один, а другие - четыре или пять.

Это означает, что у меня может быть любая перестановка этих пяти интерфейсов.В классической модели мне пришлось бы реализовать 32-5 = 27 «метаинтерфейсов», которые «объединяют» интерфейсы в связку. Часто это не проблема, потому что IB обычно расширяет IA и т.д., но в моем случае пять интерфейсов ортогональны / независимы.

В моем коде фреймворка есть методы, которым нужны экземпляры, в которых реализовано любое количество этих интерфейсов. Итак, предположим, что у нас есть класс X и интерфейсы IA , IB , IC , ID и IE . X реализует IA , ID и IE .

Ситуация ухудшается, потому что некоторые из этих интерфейсов имеют параметры формального типа .

Теперь у меня есть два варианта:

  1. Я мог бы определить интерфейс IADE (или, скорее, IPersistable_MasterSlaveCapable_XmlIdentifierProvider ; подчеркивание только для вашего удовольствия от чтения)

  2. Я мог бы определить общий введите как , что даст мне удобный способ смешивать и сопоставлять интерфейсы по мере необходимости.

  3. Я мог бы использовать такой код: IA a = ...; ID d = (ID) a; IE e = (IE) e , а затем использовать локальную переменную правильного типа для вызова методов, даже если все три работают с одним и тем же экземпляром. Или используйте приведение при каждом втором вызове метода.

Первое решение означает, что я получаю много пустых интерфейсов с очень нечитаемыми именами.

Во втором используется своего рода "специальная" типизация.И Oracle javac иногда спотыкается о них, в то время как Eclipse понимает это правильно.

Последнее решение использует приведение типов. Достаточно.

Вопросы:

  1. Есть ли лучшее решение для смешивания любого количества интерфейсов?

  2. Есть ли какие-либо причины избегать временных типов, которые предлагает мне решение №2 (за исключением недостатков в Oracle javac ])?

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

[Edit] Кажется, есть некоторая путаница в том, что я пытаюсь здесь предпринять. Мои экземпляры модели могут иметь одну из следующих черт:

  • Они могут быть «способными к главному-подчиненному» (подумайте о клонировании)
  • Они могут иметь идентификатор XML
  • Они могут поддерживать операции с деревом (родительский / дочерний)
  • Они могут поддерживать версии
  • и т. Д. (да, модель еще сложнее)

Теперь у меня есть код поддержки, который работает с деревьями. Расширения деревьев - это деревья с ревизиями. Но у меня тоже есть ревизии без деревьев.

Когда я нахожусь в коде для добавления дочернего элемента в диспетчере дерева ревизий, я знаю, что каждый экземпляр должен реализовывать ITtree и IRevisionable , но нет общего интерфейса для обоих потому что это совершенно независимые проблемы.

Но в реализации мне нужно вызывать методы на узлах дерева:

public void addChild( T parent, T child ) {
    T newRev = parent.createNewRevision();
    newRev.addChild( foo );
    ... possibly more method calls to other interfaces ...
}

Если createNewRevision находится в интерфейсе IRevisionable и addChild находится в интерфейсе ITree , каковы мои варианты определения T ?

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

Я мог привести тип для каждого вызова, но это кажется неуклюжим. Создание всех перестановок интерфейсов было бы скучным, и, похоже, нет разумного шаблона для сжатия огромных имен интерфейсов. Обобщения предлагают хороший выход:

public

void addChild( T parent, T child ) { ... }

Это не всегда работает с Oracle javac , но кажется компактным и полезным. Есть ли другие варианты / комментарии?

10
задан Aaron Digulla 20 February 2012 в 15:54
поделиться