Все, що реалізує I3, потрібно буде реалізувати I1 та I2, а об'єкти з різних класів, які успадковують I3, потім можуть бути взаємозамінними (див. Нижче), тож правильно називати I3 порожнім? Якщо так, що було б кращим способом архітектури?
«Пакетування» I1
і I2
в I3
пропозиції хороший (?) Ярлик, або яке - то синтаксичний для всюди , де ви хочете і повинні бути реалізовані.
Проблема такого підходу полягає в тому, що ви не можете зупинити інших розробників від явного впровадження I1
та I2
одночасно, але він не працює обома способами - хоча : I3
це еквівалентно : I1, I2
, : I1, I2
не є еквівалентом : I3
. Навіть якщо вони функціонально однакові, клас, який підтримує і те, I1
і I2
не буде виявлено як підтримуючий I3
.
Це означає, що ви пропонуєте два способи досягнення одного і того ж - «ручний» та «солодкий» (із синтаксичним цукром). І це може погано вплинути на послідовність коду. Пропонуючи два різні способи досягти одного і того ж, тут, там, а в іншому місці - це вже 8 можливих комбінацій :)
void foo() {
I1 something = new A();
something = new B();
something.SomeI1Function();
something.SomeI2Function(); // we can't do this without casting first
}
Гаразд, ви не можете. Але, можливо, це насправді хороший знак?
Якщо I1
і I2
маються на увазі різні обов'язки (інакше не потрібно було б їх розділяти в першу чергу), то, можливо foo()
, неправильно намагатися something
виконувати два різні обов'язки за один раз?
Іншими словами, може бути, що він foo()
сам порушує принцип єдиної відповідальності, і той факт, що для його зняття потрібні перевірки типу кастингу та виконання, це червоний прапор, який нас насторожує.
Редагувати:
Якщо ви наполягаєте на тому, щоб переконатися, що foo
використовується щось, що реалізується, I1
і I2
ви можете передати їх як окремі параметри:
void foo(I1 i1, I2 i2)
І вони можуть бути тим самим об’єктом:
foo(something, something);
Що foo
байдуже, якщо вони однакові чи ні?
Але якщо це все одно (наприклад, тому що вони не є без громадянства) або ви просто вважаєте, що це виглядає некрасиво, можна замість цього використати генеричні дані
void Foo<T>(T something) where T: I1, I2
Тепер загальні обмеження дбають про бажаний ефект, не забруднюючи зовнішній світ нічим. Це ідіоматичний C #, заснований на перевірках часу компіляції, і він вважається більш правильним в цілому.
Я I3 : I2, I1
дещо сприймаю як зусилля з імітації типів об'єднання мовою, яка не підтримує його з поля (C # або Java не мають, тоді як типи об'єднання існують у функціональних мовах).
Намагання наслідувати конструкцію, яка насправді не підтримується мовою, часто є незграбною. Аналогічно, у C # ви можете використовувати методи розширення та інтерфейси, якщо хочете емулювати міксини . Можливо? Так. Гарна ідея? Я не впевнений.