Чому програміст хотів би відокремити реалізацію від інтерфейсу?


18

Модель дизайну мостів відокремлює реалізацію від інтерфейсу програми.

Чому це вигідно?


Для запобігання протікання абстракції
SK-логіка

1
Це, здається, зрозуміло вже всім, але для нових глядачів Bridge Design - це не про реалізацію та інтерфейс "програми", а про частини, можливо, навіть невеликі частини програми. Вся програма буде сукупністю інтерфейсів та реалізацій (кожен інтерфейс має одну або більше реалізацій). Перше речення, можливо, повинно бути: "Модель дизайну моста відокремлює інтерфейси від їх реалізації протягом усього вашого вихідного коду."
RalphChapin

Відповіді:


35

Це дозволяє змінювати реалізацію незалежно від інтерфейсу. Це допомагає впоратися зі зміною вимог.

Класичний приклад - це заміна реалізації пам’яті в інтерфейсі чимось більшим, кращим, швидшим, меншим або іншим чином, не змінюючи решту системи.


23

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

Наприклад, багато мов мають поняття потоку десь у стандартній бібліотеці. Потік - це те, що містить дані для послідовного доступу. У ньому є дві основні операції: Read (завантажте наступну кількість X байтів із потоку) та Write (додайте X кількість байтів даних у потік), а іноді й третю, Seek (скиньте "поточне положення" потоку на нове місце).

Це досить проста концепція, але подумайте про все, що ви могли з цим зробити. Найбільш очевидним є взаємодія з файлами на диску. Потік файлів дозволить вам прочитати дані з файлу або записати в нього. Але що робити, якщо ви хочете надіслати дані через мережеве з'єднання?

Якщо ви покладалися на реалізацію безпосередньо, вам доведеться виписати дві абсолютно різні підпрограми, щоб зберегти ті самі дані у файл або надіслати їх по мережі. Але якщо у вас є інтерфейс потоку, ви можете створити дві різні його реалізації ( FileStreamі NetworkStream), які інкапсулюють конкретні деталі надсилання даних, куди потрібно перейти, і тоді вам потрібно лише один раз написати код, який стосується збереження файлу. . Раптом ваш SaveToFileі SendOverNetworkпідпрограми набагато простіше: вони просто налаштовують потік відповідного типу і передають його в порядок SaveData, який приймає інтерфейс потоку - йому не потрібно дбати про тип, доки він може виконувати Операція запису - і зберігає дані в потоці.

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


1
Це одна з найсильніших особливостей ООП. Мені просто подобається ...
Раду Мурзеа

1
Як відрізняється ця форма за допомогою простих інтерфейсів?
vainolo

@Vainolo: Це допомагає при повторному використанні коду. Навіть якщо у вас є кілька типів потоків, всі вони робитимуть багато тих самих речей, що й один одного. Якщо ви почнете з IStreamінтерфейсу, вам доведеться винаходити весь набір функціональних можливостей для кожного потоку. Але якщо ви почнете з базового абстрактного класу потоку, він може вмістити всі загальні стани та функціональні можливості, а потім дозволити нащадкам реалізувати різні особливості.
Мейсон Уілер

2
@RaduMurzea це не характерно для OOP. Класи типу дозволяють вам робити те саме, що абсолютно не є OOP.
Уес

@ Точно, просто хотів сказати те саме, і тоді я прочитав ваш коментар.
jhegedus

4

У вас тут справді два дуже різні питання, хоча вони пов’язані між собою.

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

Загальне питання - це щось життєво важливе для кожного програміста. Саме це перешкоджає поширенню змін у програмі скрізь. Я не уявляю, як люди можуть програмувати, не використовуючи цього.

Коли ви пишете просту заяву додавання мовою програмування, це вже абстракція, (навіть якщо вона не використовує перевантаження оператора для додавання матриць чи чогось подібного), що проходить досить багато іншого коду, перш ніж він нарешті буде виконаний на схемі у вашому комп’ютері. Якби не було відокремлення інтерфейсу (скажімо, "3 + 5") від реалізації (купа машинного коду), вам доведеться міняти свій код щоразу, коли зміна реалізації (як ви хотіли запустити на новий процесор).

Навіть у простому додатку CRUD кожен підпис методу є в широкому сенсі інтерфейсом до його реалізації.

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

Це звучить прямо, але на практиці це ускладнюється.

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

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

Це насправді трохи детальніше, ніж це, тому що кожен клас дійсно може бути ієрархією класів (так, може бути не просто абстрактний текстовий процесор, а абстрактний документ, абстрактний TextSelection тощо, з конкретними реалізаціями для кожного), але це та ж ідея.

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

Це пов'язано з Inversion Of Control, оскільки конкретний реалізатор буде переданий методам або конструкторам і визначатиме фактичну названу реалізацію.

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