Як реалізувати лише частину інтерфейсу


14

Під час розробки в OOP іноді інтерфейс / контракт надається бібліотекою, яку ви не можете змінити. Назвемо цей інтерфейс Дж.

Тепер у вас є об'єкт класу A, який споживає об'єкти, що реалізують цей інтерфейс. Всередині Потрібна лише невелика частина визначень інтерфейсу. Деякі з об'єктних класів створюються мною під час проекту (назвемо один з них типу D), тому в реалізації всього інтерфейсу J є накладні витрати.

Я хочу реалізувати підмножину функціональності в інтерфейсі J, але поки що мої рішення не задовольняють мене:

  • реалізовуючи кожен аспект J, а потім кидаючи "notImplementedExceptions", дезінформує користувача моїх об'єктів: здавалося б, мої об'єкти типу D відповідають інтерфейсу J, але вони не відповідають - та іншим споживачам моїх об'єктів (які приймають об'єкти, що реалізують інтерфейс J) не можу покластися на цілісність моїх об'єктів.
  • Реалізація щойно визначеного інтерфейсу забороняє мені використовувати об'єкти, що реалізують лише інтерфейс J, хоча інтерфейс J повністю сумісний з моїм власним інтерфейсом.
  • Якщо дозволити моїм власним об'єктам реалізувати інтерфейс J, це створило б значні накладні витрати, оскільки їм не потрібна вся ця функціональність.

Коли мені вдалося змінити інтерфейс J, я створив "суперінтерфейс" K, який мав цей підмножина функціональності інтерфейсу J, і зробив інтерфейс J успадкованим від інтерфейсу K. Але я не можу змінити інтерфейс Ж.

Яке об’єктно-орієнтоване рішення цієї проблеми? Чи найкраще рішення все ж реалізує "просто" інтерфейс J? Або є OOP-способи "суперкласифікувати" інтерфейс, не змінюючи його?


1
Подивіться, як це роблять класи * Адаптер у Swing.

Відповіді:


9

якщо ви не керуєте інтерфейсом J, ви застрягли.

Ви можете, для наочності, реалізувати свій власний інтерфейс subJ та інтерфейс J, а також використовувати subJ у власному коді, щоб зрозуміти, що додаткові методи в інтерфейсі J не потрібні, але я не думаю, що це дійсно багато заробляє вас.

по можливості повністю реалізувати весь інтерфейс J

якщо можливо, зв’яжіться з власником інтерфейсу J і попросіть його / її змінити, щоб він краще відповідав вашим цілям


2
Як компроміс: Ви можете попросити власника інтерфейсу J успадкувати ваш менший інтерфейс SubJ.
k3b

27

Весь сенс реалізації інтерфейсу полягає у наданні твердого контракту між абонентом і абонентом, який ніколи не змінюється, в той час як деталі реалізації можуть відрізнятися.

Реалізуючи інтерфейс J, ви говорите зовнішньому світу, що ви можете зробити.

Якщо вам не потрібна половина того, що робить J, то або інтерфейс дійсно слід підрозділити, оскільки він не такий маленький, як міг би бути, або вам доведеться NotImplementedExceptionзастосовувати методи та властивості, які вам не потрібні. Однак це не найкраще рішення, оскільки воно бентежить очікування людей щодо того, що може зробити ваш код.


5

Якщо ваш споживчий клас A не потребує всього інтерфейсу J, я б запропонував створити новий інтерфейс (назвіть його K), який всебічно описує все, що він вимагає.

Це забезпечує чіткий сигнал для кожного, хто користується класом А, щодо того, яка їх сторона договору. Тим самим покращуються шанси повторного використання. Якщо комусь потрібно надати об’єкт, який реалізує великий і складний інтерфейс, щоб зробити щось порівняно просто, він, швидше за все, напише все, що робить клас A сам.

Для того щоб дозволити класу A споживати об'єкти, що реалізують інтерфейс J поодинці, ви можете надати обгортковий клас, який реалізує інтерфейс K і передає будь-які відповідні виклики до члена інтерфейсу J.


3

Хоча я погоджуюся з існуючими відповідями, які говорять, що вам дійсно потрібно або повністю реалізувати J (за винятком не реалізованих методів), або зовсім не можливим, можливе вирішення наступного:

  • Створіть менший інтерфейс K, який є підмножиною J, і реалізує необхідні методи.
  • Створіть обгортку для A, яка приймає об'єкти, що реалізують J та K.
  • У випадку пропуску в J просто натисніть його на екземпляр A.
  • У випадку пропуску в K, інстанціюйте анонімну реалізацію J, з'єднавши лише ті методи, які існують від K до J. Передайте результат екземпляру А.

Зверніть увагу, що це досить потворне рішення, оскільки для нього потрібна обгортка, яка приймає кілька речей, які по суті є одне і те ж. Але це дозволяє досягти наступного:

  • Жодних змін у J або A.
  • Немає "відкритих" реалізацій J, які є неповними.

Якщо ваша мова OO не дозволяє анонімне ідентифікація інтерфейсу, ви можете створити фіктивну реалізацію інтерфейсу та інстанціювати це.


1

Скільки часу займе у вас реалізація всього інтерфейсу?

Якщо це займе у вас значну кількість часу, це вказує на питання дизайну, і я б радив вам (як це робив Стівен А. до мене) звернутися до власника і подивитися, чи можна його змінити в майбутньому.

Чи використовуєте ви інтерфейс у власному коді, незалежно від бібліотеки інтерфейсу?

Як запропонував Стівен А., ви можете використовувати власний інтерфейс, як ви хотіли б бачити його у власному коді. Це принаймні забезпечує чистоту вашого домашнього коду. Ви також можете надіслати це власнику як інтерфейс, який ви очікуєте знайти. Можливо, він погоджується з вами, або, можливо, він може пояснити вам, чому інтерфейс не слід розділяти.

Чи буде Ваша реалізація коли-небудь потребувати невикористаних членів інтерфейсу?

Якщо ви можете розраховувати, що вони ніколи не дзвонять, оскільки вони "не підтримуються", я вважаю за краще використовувати NotSupportedException. Це дає чітку інформацію про те, що ви ніколи не будете підтримувати цей інтерфейс, ніж ви його не реалізували.


Хороша ідея NotSupportedExceptionйого використання дає зрозуміти, що ви не підтримуєте цей метод.
ChrisF

@ChrisF: Я використовую лише NotImplementedExceptionдля виробничого коду, де я б інакше написав "TODO: Реалізуй це". На жаль, вони не з'являються у списку завдань Visual Studio . Але на практиці я навряд чи залишаю метод без застосування упродовж більш ніж двох днів. Resharper також показує ці винятки жирним шрифтом (принаймні з моїм налаштуванням). :)
Стівен Євріс

0

Реалізуйте те, що вам потрібно, і киньте виняток NoImplementedException на інших.

Це питання використання. Якщо ви не використовуєте інтерфейс або знаєте, що ваш код не буде використовувати цей інтерфейс, тоді не вкладайте на це часу, оскільки вам не потрібно вкладати час на надмірний код.

Працюйте над завданням, і слідкуйте за іншими, якщо вони хочуть використовувати інтерфейс.

Дуже багато інтерфейсів на Java не реалізовано повною мірою.

Це підхід Apache до речей: http://commons.apache.org/lang/api-2.4/org/apache/commons/lang/NotImplementedException.html


Можливо, заперечуєте, чому ви вважаєте, що це правильне рішення. Це нічого не додає до питання.
Стівен Євріс

немає необхідності все реалізовувати, як і немає реальної потреби все пояснювати. якби це був його випадок, частини інтерфейсу були зайвими, він би забрав його негайно.
Відображувати ім’я
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.