JavaRush /Java блог /Random UA /Об'єктно-орієнтоване програмування (переклад статті)
Exidnus
38 рівень
Санкт-Петербург

Об'єктно-орієнтоване програмування (переклад статті)

Стаття з групи Random UA
Від перекладача: На жаль, я не маю скільки-небудь значного досвіду перекладу з англійської, хоча я і досить багато читаю англійською. Але з'ясувалося, що читати та перекладати – різні речі. Також, на жаль, у мене немає значного досвіду в програмуванні (нещодавно тільки зробив найпростіший веб-додаток на Spring MVC та Hibernate). Тому переклад вийшов значно гіршим, ніж міг би бути. Я взяв на себе сміливість дещо підкоригувати приклади коду, які даються в статті, оскільки вони не відповідають угодам найменування (code conventions) в Java. Можливо, не варто було перекладати назву деяких патернів (такий переклад мало що дає для розуміння), але я вважав, що це менше зло. Окремо варто сказати про "високу зчепленість" як переклад "high cohesion". Згоден, не найкращий переклад. Але "сильна зв'язність" - це "high coupling" (інше важливе поняття), а "когерентність" тут навряд чи підійде. Я відкритий для критики і з вдячністю прийму зауваження за статтею в будь-якій формі. Об'єктно-орієнтоване програмування - це стиль програмування, в якому програма складається з компонентів, що відповідають об'єктам реального світу. умов). Наприклад, олівець – це об'єкт реального світу, який має такі властивості:
  • Він червоний (це змінюється з часом).
  • Він 10 сантиметрів у довжину зараз (це може змінюватись, якщо олівець заточити).
І він має таку поведінку:
  • Він залишає слід, якщо його використовувати правильно.
  • Слід може відрізнятись залежно від тиску (залежить від зовнішніх факторів).
  • Його довжина скорочується, якщо його заточувати (постійна поведінка).
Як у цьому прикладі, об'єкти реального світу можуть мати багато властивостей, але при написанні програм ми беремо до уваги лише необхідні властивості. Об'єктно-орієнтоване програмування має переваги. Наприклад, воно полегшує встановлення зв'язку між об'єктом реального світу та програмою так, як це очікується. Це реально допомагає у міру того, як додаток зростає і безліч об'єктів взаємодіють один з одним. Це допомагає у розподілі відповідальності всередині об'єктивного світу, дозволяючи сфокусуватися на продумуванні програми. Інша важлива особливість, що асоціюється з ООП(об'єктно-орієнтованим програмуванням), – це класифікація об'єктів. Оскільки світ (реальний/віртуальний) сповнений об'єктів, складно керувати окремо. Нам потрібен спосіб класифікації цих об'єктів, який допоможе нам зв'язати різні об'єкти та їх властивості, наприклад чорний олівець. Він був би невідмінним (той самий?), Якби використовувався в попередньому прикладі, але це інший об'єкт. Але оскільки це обидва олівці, вони належать тому самому класу «Олівець». Тоді як ручка, яка дуже схожа на олівець, належить до іншого класу. Тим не менш, ручка і олівець обидва є «Пишучими інструментами». Об'єктно-орієнтоване програмування має такі принципи:
Абстракція
Абстракція визначається як характерна риса (quality) взаємодії з ідеями, а не подіями або, іншими словами, свобода від якостей, що репрезентують . Це дозволяє програмістам сфокусуватися на тому, що програмувати , а не як . Абстракцію можна розглядати як угоду, за допомогою якої ми надаємо функціональність. Деталі реалізації можуть бути приховані, якщо використати цей концепт. Наприклад, якщо нам потрібен клас, який пише, то ми повинні бути впевнені, що має методи «писати» abstract class writer { write (); } Що ми зробабо? Ми розробабо клас високого рівня, що є абстрактними, іншими словами, він знає, що за функціональність нам потрібна, але як її реалізувати – це поза видимістю (out of scope) даного класу. Це дає багато переваг:
  • Ми розкриваємо мінімум інформації необхідної зовнішнім сутностям, це дозволяє зосередитись на продумуванні програми (this enable focused thinking), уникнути плутанини та не давати ненавмисних обіцянок.
  • Ми залишаємо місце для покращень у майбутньому, які були б неможливі, якщо деталі реалізації були розкриті.
успадкування
«Спадкування» у загальновживаній англійській означає «набувати і передавати далі». Це слова існує у нашій культурі дуже давно. Батьки купували землю за допомогою важкої роботи і передавали її своїм дітям, навіть природа благоволіє спадкоємству. Всі властивості тіла, наприклад, ріст, колір шкіри/очей/волосся і т.д. залежить від генів, успадковуємо нами від батьків. Спадкування запобігає винаходу колеса заново і прискорює прогрес. Те саме і в ООП. Ми створюємо батьківський клас з кількома базовими властивостями/поведінкою. Всі класи, що успадковуються від цього батька, будуть містити такі властивості/поведінка, що й їхній батько. Тим не менш, успадковані класи можуть отримати більше властивостей/поведінки або змінити реалізацію поведінки. class WritingInstrument { colour; write() { } } class Pen (child of parent) { inkcolour; } У прикладі зверху клас-батько (WritingInstrument) має властивість «колір» та поведінку «писати». Коли клас-спадкоємець (ручка) оголошується, повторне оголошення властивості «колір» та поведінки «писати» не потрібно. Вони є у класі «ручка» з успадкування. Проте клас-спадкоємець може оголосити власні додаткові властивості/поведінку. Як ми можемо використовувати це практично? Ми, розробники, дуже ліниві. Ми не хочемо друкувати щось знову і знову. Існування безлічі копій одного й того ж коду не вітається через такі міркування:
  • Що менше копій коду, то легше його супроводжувати.
  • Якщо немає безлічі копій коду, то зміна в одному місці стає видимою скрізь.
  • Чим менше коду – тим менше помилок.
  • Якщо один код використовується в багатьох місцях, то досягається узагальнення.
  • Ми фокусуємось на написанні коду.
  • Ми фокусуємось на тестах.
Спадкування в Java досягається за допомогою ключових слів extends і implements. class WritingInstrument { } class Pen extends WritingInstrument { }
Поліморфізм
Слова «поліморфізм» походить від двох слів: «Полі» , тобто. «Більшість» / «більше, ніж один» «морф» , тобто. «форма» Буквально, слово «поліморфізм» відсилає здатність об'єктів поводитися по-різному залежно від умов. У програмуванні поліморфізм може бути втілений у кількох місцях:
  • Класи
  • Методи
  • Оператори
Все, перераховане вище, може поводитися по-різному залежно від умов, можливо, від контексту, у яких вони використовуються. Це корисно, оскільки клієнту (програмісту, який використовує ваші бібліотеки) не потрібно знати безліч тонкощів, і бажана функціональність реалізується за допомогою відбору необхідної інформації з контексту. Class WritingObject { wrire() { // пишем, используя стандартные (по дефолту) цвета } } class Pencil extends WritingObject { write() { // пишем, используя серый цвет, написанный текст можно стереть } } class Pen extends WritingObject { write() { // пишем, используя голубой цвет, написанный текст нельзя стереть } } class Main { main() { WritingObject wr = new WritingObject(); wr.write(); // первый вызов WritingObject wr = new Pen(); wr.write(); // второй вызов WritingObject wr2 = new Pencil(); wr2.write(); // третий вызов } } У прикладі вище має реалізація за умовчанням WritingObject, яка розширена/перевизначена класами-спадкоємцями перо і ручка. Метод write() викликаний тричі у класі Main. Щоразу викликається різна реалізація залежно від цього, якого об'єкта викликається цей метод. У разі метод write() має безліч типів поведінки, оскільки він полиморфичен.
Інкапсуляція
Інкапсуляція визначається як збір пов'язаних даних/функціональностей в одному модулі (unit). Це допомагає у полегшенні доступу/модифікації даних. Наприклад, якщо нам потрібно надрукувати всі властивості, які користувач має, ми маємо наступні опції: printUserProperties(userName, userId, firstname, lastname, email, phone, … … ….) Ми створабо метод, який приймає всі властивості і друкує їх один за одним. Зі збільшенням кількості елементів у списку зникне можливість ідентифікувати коректні поля, а додавання/видалення одного поля змінить сигнатуру методу. Тому нам потрібно замінити всіх користувачів цього методу, якщо навіть нещодавно додані поля їм не потрібні. Щоб зробити код більш читаним та спростити майбутні модифікації простіше, ми інкапсулюємо властивості у класі та перетворюємо його на колективний об'єкт (collective object) class User { userName userId firstname lastname email phone .. .. .. } printUserProperties(user) {} Об'єкт – це система (software bundle) змінних та пов'язаних методів. Ви можете уявити об'єкти реального світу, використовуючи об'єкти програми. Ви можете уявити реальних собак в анімаційній програмі або реальний велосипед як програмний об'єкт усередині велотренажера. В ООП клас – шаблон, що розширюється (program-code-template) для створення об'єктів, забезпечення їх початковим станом (змінні) та реалізацією поведінки (функції, методи). Абревіатура SOLID була введена Michael Feather'ом для перших п'яти принципів, названих так Robert C. Martin'ом на початку 2000-х. Метою принципів, що реалізуються спільно, є збільшення ймовірності того, що програміст створить систему, яку легко буде підтримувати та розширювати. Принципи SOLID- орієнтири у розробці програм, які необхідні для видалення «протухлого» коду за допомогою рефакторингу, в результаті якого код повинен стати легко читається та розширюється. Це частина стратегії agile and adaptive programming (гнучкого програмування, що адаптується).
Принцип єдиної відповідальності (Single Responsibility Principle)
В ООП принцип єдиної відповідальності свідчить, кожен клас має відповідати за частину функціональності, що забезпечується програмою, і що відповідальність має бути повністю інкапсульована цим класом. Вся його функціональність має бути тісно пов'язана з цією відповідальністю.
Принцип відкритості/закритості (Open/Closed Principle)
В ООП принцип відкритості/закритості свідчить про «сутність програмного забезпечення (класи, модулі, методи тощо) повинні бути відкриті для розширення, але закриті для зміни». Іншими словами, сутність має дозволяти розширювати її поведінку без зміни вихідного коду.
Принцип підстановки Ліскової (Liskov Substitution Principle)
Можливість підстановки (Substituability) – це принцип ООП. Він говорить, що якщо S у комп'ютерній програмі є підтипом T, то об'єкти типу T повинні бути такими, щоб їх можна було замінити об'єктами типу S (тобто об'єкти типу S можуть замінити об'єкти типу T) без зміни будь-яких необхідних властивостей програми (точність, виконання завдання тощо).
Принцип розподілу інтерфейсу (Interface Segregation Principle)
Принцип поділу інтерфейсу говорить, що програміст-клієнт не повинен бути змушений залежати від способів, які він не використовує. Відповідно до цього принципу потрібно розділяти великі інтерфейси на маленькі і більш специфічні, щоб програміст-клієнт знав лише методи, які йому цікаві. Метою принципу поділу інтерфейсу є збереження системи у незв'язаному стані (system decoupled), що полегшить рефакторинг, внесення змін та повторне розгортання (redeploy).
Принцип інверсії залежностей (Dependency Inversion Principle)
У ООП принцип інверсії залежності означає специфічну форму незв'язності програмних модулів. При дотриманні цього принципу стандартні відносини залежності, встановлені від модулів високого рівня, що формують архітектуру програми (policy-setting) до залежних модулів низького рівня, інвертовані (навернені), тому змінені модулі високого рівня стають незалежними від деталей реалізації модулів низького рівня. Цей принцип стверджує:
  • Модулі високого рівня повинні залежати від модулів низького рівня. Модулі обох типів мають залежати від абстракцій.
  • Абстракції повинні залежати від деталей реалізації. Деталі мають залежати від абстракцій.
Принцип звертає (inverts) шлях, згідно з яким люди можуть думати про об'єктно-орієнтований дизайн, стверджуючи, що об'єкти високого та низького рівнів повинні залежати від тих самих абстракцій.

Принципи GRASP

Паттерни (принципи), що використовуються для вирішення спільних завдань щодо призначення обов'язків класам та об'єктам (General Responsibility Assignment Software Patterns (GRASP)) містять посібники (guidelines) щодо призначення відповідальності класам та об'єктам в об'єктно-орієнтованому дизайні.
Контролер (Controller)
Паттерн Контролер призначає відповідальність за взаємодію із системними подіями класів без графічного інтерфейсу, які представляють всю систему або use case scenario (сценарії варіантів використання). Контролер:
  • Це не взаємодіє безпосередньо з користувачем об'єкт, відповідальний за отримання та реакцію на системні події.
  • Повинен використовуватися так, щоб мати справу з усіма системними подіями одного (або безлічі взаємопов'язаних) use cases.
  • Це перший об'єкт за графічним інтерфейсом, що контролює системні операції.
  • Він повинен робити роботу сам, його завдання – контроль над потоком подій.
Творець (Creator)
Завдання класу-творця – створення та ініціація об'єктів для подальшого використання. Він знає, параметри ініціалізації, а також який об'єкт буде створено. Іноді клас-творець створює об'єкти активно і поміщає в кеш, і забезпечує один екземпляр, що він потрібен.
Висока зчепленість (High Cohesion)
Висока зчепленість - оцінний патерн, метою застосування якого є збереження об'єктів у такому стані, щоб вони були націлені на виконання одного чіткого завдання, легко керовані та розуміються. Висока зчепленість зазвичай використовується підтримки слабкої зв'язності (Low Coupling). Висока зв'язність означає, що відповідальність цього елемента чітко позначена (strongly related and highly focused). Розбиття програми на класи та підсистеми – приклад дій, що підвищує зчепленість властивостей системи. Слабка зчепленість, навпаки, - ситуація, у якій елемент має дуже багато незв'язаних завдань. Елементи зі слабкою зчепленістю зазвичай відрізняються тим, що їх важко зрозуміти, важко повторно використовувати, підтримувати та змінювати.
Окольний шлях (Indirection)
Паттерн Кільцевий шлях підтримує слабку зв'язність (і можливість повторного використання) між двома елементами, призначаючи відповідальність за взаємодію між ними проміжному об'єкту. Прикладом є введення контролера для посередництва між даними (моделлю) та їх відображенням (поданням) у патерні Модель-Подання-Контролер (MVC).
Інформаційний експерт (Information Expert)
Інформаційний експерт (також Експерт чи принцип Експерта) – принцип, який використовується визначення того, кому делегувати відповідальність. Відповідальність включає методи, що обчислюються поля тощо. При використанні даного принципу при призначенні відповідальності основним підходом є така послідовність дій: аналіз відповідальності, визначення інформації, яка потрібна для її виконання, нарешті, встановлення того, де ця інформація знаходиться. Використання принципу Інформаційний експерт призводить до призначення відповідальності класу, який має найбільшу кількість інформації для виконання.
Слабка зв'язність (Low Coupling)
Слабка зв'язність – оціночний патерн, який вказує, як призначати відповідальність: слабка залежність між класами, зміна одного повинна мати мінімальні наслідки для іншого, максимальну можливість повторного використання.
Поліморфізм (Polymorphism)
Відповідно до поліморфізму зміни поведінки ґрунтується на типі об'єкта, на який посилається змінна. Це досягається використанням поліморфних операцій.
Захищені зміни (Protected Variations)
Паттерн Захищені зміни захищає елементи від змін інших елементів (об'єктів, систем, підсистем) шляхом обгортання центру нестабільності (the focus of instability) інтерфейсом та використання поліморфізму для створення різних реалізацій цього інтерфейсу.
Чисте конструювання (Pure Fabrication)
Чисте конструювання передбачає клас, який не представляє концепт у проблемній галузі (the problem domain) і створений спеціально для досягнення слабкої зв'язності, високої зчепленості і, отже, максимального потенціалу повторного використання (рішення, пропоноване патерном Інформаційний експерт цього не забезпечує). Такий клас зазвичай називається “Service” у Предметно-орієнтованому дизайні (Domain-driven design).

Критика

Дослідження Potok'a та ін. показали відсутність суттєвих відмінностей між ООП та процедурними підходами.
Критичне порівняння ООП з іншими технологіями, особливо реляційними, утруднене через відсутність визначення ООП, яке було б строгим і широко прийнятим (Christopher J. Date)
У порівнянні з іншими мовами (LISP діалекти, функціональні мови тощо) ООП мови не мають унікальної переваги та нав'язують непотрібну складність. (Lawrence Krubner)
Я знаходжу об'єктно-орієнтоване програмування технічно безпідставним. Воно намагається розкласти світ на частини у термінах інтерфейсів, які змінюються у межах одного типу. Щоб мати справу з реальними проблемами, вам потрібні багатосортні алгебри - сімейства інтерфейсів, які сягають багатьох типів. Я знаходжу об'єктно-орієнтоване програмування філософськи хворим. Воно стверджує, що це є об'єктом. Навіть якщо це так, це не дуже цікаво: сказати, що все є об'єктом - отже, не сказати взагалі нічого. (Олександр Степанов)
Популярність ООП серед великих компаній пов'язана з "великими (і часто змінюються) групами посередніх програмістів". Дисципліна, що нав'язується ООП, запобігає нанесенню програмістом «надто великої шкоди». (Paul Graham)
Об'єктно-орієнтоване програмування ставить іменники першими і найголовнішими. Навіщо йти на такі крайні заходи та ставити одну частину мови на п'єдестал? Чому один концепт отримує перевагу над іншим? Це неможливо, щоб ООП раптово зробило дієслова менш важливими для нашого мислення. Це дивним чином перекошена перспектива. (Steve Yegge)
Rick Hickey, творець Clojure, описував об'єктні системи як украй спрощені моделі реального світу. Він підкреслював нездатність ООП моделювання часу правильно, що створює величезні проблеми, як у програмах велике поширення набуває багатопоточність. Eric S. Raymond, Unix-програміст і прихильник програмного забезпечення з відкритим кодом, був критично налаштований щодо заяви, що ООП є "Єдино вірним рішенням", і писав, що ООП заохочує багатошарові програми, що перешкоджає зрозумілості (transparency). Як протилежний підхід Raymond наводив приклад Unix і С.

Посилання

By Margaret Rouse @ WhatIs.com Wikipedia! ( Російський варіант ) inheritance is polymorphism SOLID (Object Oriented Design) ( Російський варіант ) Single Responsibility PrincipleArguments against OOPS ( Російський варіант ) What is OOPS (without the hype) Переклад: Варигін Д.В.
Коментарі
ЩОБ ПОДИВИТИСЯ ВСІ КОМЕНТАРІ АБО ЗАЛИШИТИ КОМЕНТАР,
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ