У меня есть ситуация, когда у меня есть много классов моделей (~ 1000), которые реализуют любое количество из 5 интерфейсов.Итак, у меня есть классы, которые реализуют один и другие, которые реализуют четыре или пять.
Это означает, что я могу иметь любую перестановку этих пяти интерфейсов.В классической модели мне пришлось бы реализовать 32-5 = 27 «метаинтерфейсов», которые «объединяют» интерфейсы в связке.Зачастую это не проблема, потому что IB
обычно расширяет IA
и т. Д., Но в моем случае пять интерфейсов являются ортогональными / независимыми.
В моем фреймворковом коде у меня есть методы, которым нужны экземпляры, которыеиметь любое количество реализованных этих интерфейсов.Итак, давайте предположим, что у нас есть класс X
и интерфейсы IA
, IB
, IC
, ID
и IE
.X
реализует IA
, ID
и IE
.
Ситуация ухудшается, поскольку некоторые из этих интерфейсов имеют параметры формального типа .
I сейчасесть две опции:
Я мог бы определить интерфейс IADE
(точнее IPersistable_MasterSlaveCapable_XmlIdentifierProvider
; подчеркивает только для вашего удовольствия от чтения)
Я мог бы определить универсальный тип как <T extends IPersistable & IMasterSlaveCapable & IXmlIdentifierProvider>
, что дало бы мне удобный способ смешивать и сопоставлять интерфейсы по мере необходимости.
Я мог бы использовать такой код: IA a = ...; ID d = (ID)a; IE e = (IE)e
изатем используйте локальную переменную с правильным типом для вызова методов, даже если все три работают на одном экземпляре.Или используйте приведение в каждом втором вызове метода.
Первое решение означает, что я получаю много пустых интерфейсов с очень нечитаемыми именами.
Вторая использует своего рода «специальную» типизацию.И Oracle 1045 * иногда натыкается на них, в то время как Eclipse делает это правильно.
Последнее решение использует приведение типов.Nuff сказал.
Вопросы:
Есть ли лучшее решение для смешивания любого количества интерфейсов?
Есть ли какие-либопричины избегать временных типов, которые предлагает мне решение № 2 (за исключением недостатков в Oracle javac
)?
Примечание: я знаю, что написание кода, который не компилируется сOracle javac
- это риск.Мы знаем, что мы можем справиться с этим риском.
[Редактировать] Кажется, есть некоторая путаница в том, что я пытаюсь предпринять здесь.Экземпляры моей модели могут иметь одну из этих черт:
- Они могут быть "способными к ведению подчиненного" (например, клонирование)
- Они могут иметь идентификатор 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
<T extends IRevisionable & ITree>
void addChild( T parent, T child ) { ... }
Это не всегда работает с Oracle javac
, но кажется компактным и полезным.Любые другие варианты / комментарии?