Плюси і мінуси обєктно-орієнтованого програмування

09.09.2015

(c) 1993, Springer-Verlag

Відомості про автора

Ханспетер Мессенбок (Hanspeter Moessenboeck) — відомий фахівець в області компіляторів, мов і систем програмування, об’єктно-орієнтованого програмування, програмної інженерії; розробник експериментального мови Object Oberon, разом з Никлаусом Віртом (Niklaus Wirth) є творцем мови Oberon-2. Він брав участь у ряді проектів, що проводяться в Швейцарському Федеральному технологічному інституті (Swiss Federal Institute of Technology), був професором кафедри комп’ютерних наук (Computer Science Department) в ETH (Цюріх, Швейцарія). Він автор відомої книги «Object-Oriented Programming in Oberon-2» (Springer-Verlag, 1993). В даний час працює професором в універсітеті Йоганна Кеплера в Лінці (Johannes Kepler University, Linz, Austria).

Анотація

Ця глава з книги Х. Мессенбока «Object-Oriented Programming in Oberon-2» являє собою чудове лаконічний виклад переваг і недоліків об’єктно-орієнтованого програмування. Зачіпаються такі питання, як розширюваність систем, накладні витрати на підтримку ООП і виробництво закінчених програмних продуктів з напівфабрикатів.

Ключові слова

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

У цій книзі ми намагалися показати, в яких ситуаціях класи корисні, а коли їх використовувати не слід. Тепер Давайте підведемо деякі підсумки і задамося такими питаннями.

  • Чому нам слід програмувати об’єктно-орієнтованим способом, а не процедурним?
  • Які плюси і мінуси об’єктно-орієнтованого програмування?
  • чи Переважують переваги наявні недоліки?

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

1. ПЕРЕВАГИ ООП

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

  • Класи дозволяють проводити конструювання з корисних компонент, що володіють простими інструментами, що дає можливість абстрагуватися від деталей реалізації.
  • Дані та операції разом утворюють певну сутність і вони не «розмазуються» по всій програмі, як це нерідко буває у разі процедурного програмування.
  • Локалізація коду і даних покращує наочність і зручність супроводу програмного забезпечення.
  • Інкапсуляція інформації захищає найбільш критичні дані від несанкціонованого доступу.

ООП дає можливість створювати розширювані системи (extensible systems). Це одне з найбільш значних переваг ООП і саме воно відрізняє даний підхід від традиційних методів програмування. Розширюваність (extensibility) означає, що існуючу систему можна змусити працювати з новими компонентами, причому без внесення до неї будь-яких змін. Компоненти можуть бути додані на етапі виконання.

Розширення типу (type extension) і випливає з нього поліморфізм змінних виявляються корисними переважно в наступних ситуаціях.

  • Обробка різнорідних структур даних. Програми можуть працювати, не обтяжуючи себе вивченням виду об’єктів. Нові види можуть бути додані в будь-який момент.
  • Зміна поведінки під час виконання. На етапі виконання один об’єкт може бути замінений іншим. Це може призвести до зміни алгоритму, в якому використовується даний об’єкт.
  • Реалізація родових компонент. Алгоритми можна узагальнювати до такої міри, що вони вже зможуть працювати більш ніж з одним видом об’єктів.
  • Доведення напівфабрикатів. Компоненти немає потреби підлаштовувати під певну програму. Їх можна зберігати в бібліотеці у вигляді напівфабрикатів (semifinished products) і розширювати по мірі необхідності до різних закінчених продуктів.
  • Розширення каркаса. Незалежні від додатка частини предметної області можуть бути реалізовані у вигляді каркаса і в подальшому розширені за рахунок додавання частин, специфічних для конкретного додатка.

Багаторазового використання програмного забезпечення на практиці досягти не вдається з-за того, що існуючі компоненти вже не відповідають новим вимогам. ООП допомагає досягти цього без порушення роботи вже наявних клієнтів, що дозволяє нам витягти максимум з багаторазового використання компонент.

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

2. НЕДОЛІКИ ООП

Об’єктно-орієнтоване програмування вимагає знання чотирьох речей.

(1) Необхідно розуміти базові концепції, такі як класи, успадкування та динамічне зв’язування. Для програмістів, знайомих з поняттям модуля і з абстрактними типами даних, це вимагає мінімальних зусиль. Для тих же, хто ніколи не використовував інкапсуляцію даних, це може означати зміни світогляду і може відняти на вивчення значну кількість часу.

(2) Багаторазове використання вимагає від програміста познайомитися з великими бібліотеками класів. А це може виявитися складніше, ніж навіть вивчення нової мови програмування. Бібліотека класів фактично являє собою віртуальний мову, який може включати в себе сотні типів і тисячі операцій. У мові Smalltalk, наприклад, до того, як перейти до практичного програмування, потрібно вивчити значну частину його бібліотеки класів. А це теж вимагає часу.

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

(4) Дуже важко вивчати класи, не маючи можливості їх «помацати». Тільки з придбанням невеликого досвіду можна впевнено себе відчути при роботі з використанням ООП.

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

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

Документування класів — завдання більш важка, ніж це було у випадку процедур і модулів. Оскільки будь-який метод може бути перевизначено у документації має йтися не тільки про те, що робить даний метод, але також і про те, в якому контексті він викликається. Адже перевизначені методи зазвичай викликаються не клієнтом, а самим каркасом. Таким чином, програміст повинен знати, які умови виконуються, коли викликається даний метод. Для абстрактних методів, які порожні, в документації має навіть говориться про те, для яких цілей передбачається використовувати переопределяемый метод.

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

Методи, як правило, коротше процедур, оскільки вони здійснюють тільки одну операцію над даними. Зате кількість методів набагато вище. Короткі методи володіють тим перевагою, що в них легше розбиратися, незручність ж їх пов’язано з тим, що код для обробки повідомлення іноді «розмазаний» по багатьом маленьким методів.

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

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

Часто можна чути, що ООП є неефективним. Як же справа насправді? Ми повинні чітко проводити межу між неефективністю на етапі виконання, неэффектиностью в сенсі розподілу пам’яті і неефективністю, пов’язаної з надмірною універсалізацією.

(1) Неефективність на етапі виконання. У мовах типу Smalltalk повідомлення інтерпретуються під час виконання програми шляхом здійснення пошуку їх в одній або кількох таблицях і за рахунок вибору відповідного методу. Звичайно, це повільний процес. І навіть при використанні найкращих методів оптимізації Smalltalk-програми в десять разів повільніше оптимізованих C-програм [Cha92].

У гібридних мовах типу Oberon-2, Object Pascal та C++ посилка повідомлення призводить лише до викликом через покажчик процедурної змінної. На деяких машинах повідомлення виконуються лише на 10% повільніше, ніж звичайні процедурні виклики. І оскільки повідомлення зустрічаються в програмі набагато рідше інших операцій, їх вплив на час виконання впливу практично не робить.

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

(2) Неефективність в сенсі розподілу пам’яті. Динамічне зв’язування і перевірка типу на етапі виконання вимагають по ходу роботи інформації про тип об’єкта. Така інформація зберігається в дескрипторі типу, і він виділяється один на клас. Кожен об’єкт має невидимий курсор на дескриптор типу для свого класу. Таким чином, об’єктно-орієнтованих програмах необхідна додаткова пам’ять виражається в одному покажчику для об’єкта і в одному дескрипторі типу для класу.

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

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

Інший підхід — дати можливість компоновщику видаляти зайві методи.

Такі інтелектуальні компонувальники вже доступні для різних мов і операційних систем.

Oberon обрав третій шлях позбавлення від зайвої універсальності.

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

Таким чином, не можна стверджувати, що ООП взагалі неефективно.

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

3. МАЙБУТНЄ ООП

Виживе об’єктно-орієнтоване програмування, або воно лише модна пошесть, яка скоро зникне?

Класи знайшли своє місце в більшості сучасних мов програмування. Одне лише це говорить про те, що їм судилося залишитися. Класи в самому найближчому майбутньому увійдуть у стандартний набір концепцій для кожного програміста, точно так само, як багато сьогодні застосовують динамічні структури даних і рекурсію, які двадцять років тому були в дивину. У той же час класи — це просто ще одна нова конструкція поряд з іншими. Нам потрібно дізнатися, для яких ситуацій вони підходять, і тільки тут ми і будемо їх використовувати. Правильно вибрати інструмент для конкретної задачі — обов’язково для кожного майстрового і ще більшою мірою для кожного інженера.

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

ЛІТЕРАТУРА

  • [Cha92] Chambers C. (1992) «The Design and Implementation of the SELF Compiler, an Optimizing Compiler for Object-Oriented Programming Languages» // Stanford University, Ph.D. thesis.

    Короткий опис статті: об’єктно орієнтоване програмування

    Джерело: Плюси і мінуси об’єктно-орієнтованого програмування

  • Також ви можете прочитати