Ця стаття присвячена створенню моделі даних, яка красиво лягала б на SQL і містила в собі «правильне» ООП спадкування. Треба сказати, що ця задача виникала у мене в різний час на різних проектах, і вирішувалася вона там теж по-різному. Назви підходів взяті з ситуації на відповідних проектах термінології.

Читати далі →

Композиція і інтерфейси

У світі об'єктно-орієнтованого програмування вже досить давно піддається критиці концепція успадкування.
Аргументів достатньо багато:

  • дочірній клас наслідує всі дані і поведінку батьківського, що потрібно не завжди (а при доопрацюванні батьківського у дочірній клас взагалі потрапляють дані і поведінка, які не передбачалися на момент розробки дочірнього);
  • віртуальні методи менш продуктивні, а в разі, якщо мова дозволяє оголосити невиртуальный метод, то як бути, якщо у спадкоємця потрібно його перекрити (можна позначити метод словом new, але при цьому не буде працювати поліморфізм, і використання такого об'єкта може привести до очікуваного поведінки, залежно від того, до якого типу наведено об'єкт в момент його використання);
  • якщо виникає необхідність множинного спадкування, то в більшості мов воно відсутнє, а там, де є (C++), вважається трудомістким;
  • є завдання, де спадкування як таке не може допомогти — якщо потрібен контейнер елементів (безліч, масив, список) з єдиним поведінкою для елементів різних типів, і при цьому потрібно забезпечити статичну типізацію, то тут допоможуть узагальнення (узагальнення).
  • і т. д. і т. п.
Альтернативою спадкоємства є використання інтерфейсів і композиція. (Інтерфейси давно використовується в якості альтернативи множинного спадкоємства, навіть якщо в ієрархії класів активно використовується спадкування.)

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

А як можна вирішити цю задачу (відсутність дублювання коду) у разі композиції і інтерфейсів?
Цій темі і присвячена ця стаття.

Читати далі →

Коротка замітка про спадкування в Node.js

JavaScript існує безліч різних способів спадкування, класового і прототипного, фабричного та через домішки, прямого і непрямого, а так само гібриди декількох методів. Але у Node.js є його рідний спосіб із застосуванням util.inherits(ChildClass, ParentClass). До недавнього часу я використовував нодовский спосіб тільки для вбудованих класів (коли потрібно зробити свого спадкоємця для EventEmitter, Readable/Writable Stream, Domain, Duffer і т. д.), а для моделювання предметної області застосовував загальновживані для всього JavaScript практики. І ось, вперше, знадобилося реалізувати власну ієрархію системних класів, не спадкоємців від вбудованих, але і не класів предметної області, а класів, масово розбито в системному коді сервера додатків Impress. І простого використання util.inherits вже якось не вистачило, я пошукав статті і не знайшовши повністю все, що мені потрібно, вивчив приклади спадкування в исходниках самої ноди, подумав і зробив приклад рідного нодовского спадкування собі на пам'ять і написав цю невелику замітку, щоб вона, сподіваюся, допомогла ще й вам. Одразу попереджаю, що реалізація виклику методу батьківського класу з переопределенного в дочірньому класі методу, мені не дуже подобається через громіздкість, тому, вітаю альтернативні способи та запрошую коммитить їх у сховище або на коментарі до цієї замітці.


Читати далі →

Відповідь на Гратчасте спадкування

Ця публікація — відповідь на текст «Гратчасте спадкування», опублікований хабрапользователем potan, з пропозицією альтернативи, на суб'єктивний погляд автора, більш близькою до ООП з класами.

Читати далі →

Гратчасте спадкування

Спадкування, при уявній простоті, часто призводить до складних, чинять опір змінам структурам. Ієрархії класів ростуть як справжній ліс.
Метою спадкування є прив'язка коду (набору методів) до мінімального набору властивостей сутності (як правило — об'єкта), які він забезпечує і які йому потрібні. Це спрощує повторне використання, тестування та аналіз коду. Але набори властивостей з часом стають дуже великими, починають перетинатися нетривіальним чином. І в структурі класів з'являються міксини та інше множинне спадкування.
Внести зміни в глибині ієрархії стає проблематично, доводиться думати наперед про «запровадження залежностей», розробляти і використовувати складні інструменти рефакторінгу.

Можливо всього цього уникнути? Варто спробувати — нехай методи будуть прив'язані до безлічі характерних властивостей об'єкта (тегів), а ієрархія наслідування вибудовується автоматично за вкладеності цих множин.

Нехай ми розробляє ієрархію для ігрових персонажів. Частину коду буде спільна для всіх персонажів — вона прив'язана до порожнього набором властивостей. Код, відповідальний за їх відображення буде представлений у вигляді варіантів для OpenGL і DirectX різних версій. Що буде залежати від раси персонажа, що від наявності та виду магічних здібностей і тп. Теги персонажа первинні. Вони перераховуються явно, а не успадковуються. А реалізація успадковується в залежності від набору тегів (за вкладеності). Таким чином вміння стріляти з ПЗРК не виявиться у кенгуру, тому що його успадкували від піхотинця.

Ідея такого підходу була запропонована Дмитром Кімом. Автор не став її втілювати в код, я спробую виправити це упущення.
Реалізація такого підходу на Clojure, як зазвичай, на github.

Читати далі →

Короткий конспект по мові JavaScript

Я -.NET розробник. Але останнім часом все частіше стикаюся з JavaScript. Причому, в 50 відсотках випадків, я щось на ньому пишу, в інших 50 — розбираюся з чужим кодом, та ще й пройшли через минификацию, а іноді і обфускацію. У цій статті захотілося поділитися тими моментами, які мені здалися важливими для розуміння мови і ефективної роботи з ним. Тут не буде нічого нового чи невідомого для людей, які вже мали справу з мовою, і не буде чогось такого, чого не можна знайти в інших джерелах. Для мене стаття буде корисна як спосіб краще розібратися в предметі, для читачів, я сподіваюся, — як привід освіжити знання.

Брендан Айк згадував, що JavaScript був створений за 10 днів. Думаю, ідея виношувалася довше. Як би те не було, мова вийшов і з тих пір тільки набирає популярність. Особливо після появи AJAX.

JavaScript — мова зі слабкою динамічною типізацією, автоматичним управлінням пам'яттю і прототипным спадкуванням.

JavaScript складається з трьох відокремлених частин:

  • ядро (ECMAScript),
  • об'єктна модель браузера (Browser Object Model або BOM),
  • об'єктна модель документа (Document Object Model або DOM).


У статті, в основному, піде мова про ядрі. Звичайно, у прикладах коду будуть використовуватися елементи DOM і BOM, але загострювати на них увагу не буду.


Читати далі →

Спадкування комбінаторних парсерів на Julia

Комбінаторні (монадические) парсери досить добре відомі (вікіпідручник). Вони представляють із себе бібліотеку маленьких парсерів, які розпізнають прості елементи граматики, і способи об'єднувати кілька парсерів в один (комбінувати — звідси й назва). Монадические вони бо один із способів комбінування, породження парсера залишку тексту на основі результату розбору початку, задовольняє умовам, накладається на математичний об'єкт «монада». У мові Haskell це дозволяє скористатися потужним сервісом, що надаються мовою і бібліотеками. В інших мовах назва «монадические» можна сміливо ігнорувати — це не буде заважати їх реалізації і використання, включаючи згадану вище операцію «bind».

Найпростіше комбінаторні парсери реалізуються у мовах з підтримкою замикань, але можна скористатися і класичним ООП (приклад описаний Rebecca Parsons в книзі Мартіна Фаулера «Предметно-орієнтовані мови»).
До переваг комбінаторних парсерів відноситься простота використання (запис мовою програмування практично не відрізняється від звичайного опису граматики), незалежність від препроцесора (як yacc/bison, happy або ocamlyacc), можливість реалізувати деякі елементи, погано укладаються в контекстно-вільну граматику, прямо на мові програмування загального призначення.

До недоліків — складність складання повідомлень про помилку, нездатність працювати з леворекурсивной граматикою (призводить до зациклювання), а так само те, що дуже легко зробити цей парсер не ефективним по швидкодії і пам'яті. (Одна з причин — компілятор не може здійснити оптимізацію в термінах граматики, так як працює на рівні мови програмування. Але є і інші тонкощі, що потребують уваги, якщо потрібно ефективність.)
Як альтернативу можна розглянути реалізації у вигляді макросів (наприклад, OCaml streams parsers). У Perl6 підтримка граматик вбудована в мову.

СпадкуванняПерсер конкретної мови складається з безлічі більш спеціалізованих парсерів, посилаються один на одного. В цьому відношенні парсери нагадують методи якогось об'єкта. Виникає бажання породжувати парсери нових версій мов, підміняючи окремі подпарсеры (як це робиться в паттерні проектування «шаблонний метод» з ООП). Для експериментів з цим підходом (а так само в порядку вивчення чергового мови) я вибрав мову Julia — динамічно-типизированном з особливим підходом до спадкоємства (подібного CLOS з Common Lisp та R).
На відміну від звичайних комбінаторних парсерів, підхід з спадкуванням є експериментальним (хоча в деякому вигляді підтримується бібліотекою макросів OCaml і мовою Perl6). Поки він породжує не дуже читабельний код. Вихідний код доступний на Github.

Читати далі →

Виразний JavaScript: Таємне життя об'єктів

Зміст



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

Джо Армстронг, в інтерв'ю Coders at Work


Термін «об'єкт» в програмуванні сильно перевантажений значеннями. У моїй професії об'єкти — стиль життя, тема священних воєн і улюблене заклинання, що не втрачає своєї магічної сили.

Сторонній людині все це незрозуміло. Почнемо з короткої історії об'єктів як концепції в програмуванні.

Читати далі →