© 03.06.2025
Александр Легалов
Мое знакомство с объектно-ориентированным (ОО) подходом состоялось в 1991 году. Оно было связано с появлением среды разработки Turbo C++ 1.0 компании Borland в "неофициальном исполнении" на паре трехдюймовых дискет. Наряду с этим нашелся текстовый файл с переводом первой редакции книги Б. Страуструпа по языку C++. Это пробудило интерес к основам ОО программирования (ООП).
Дополнительным стимулом, как разработчика экспериментального языка параллельного программирования и его компилятора, было любопытство, связанное со сравнением новых подходов к написанию и трансформации кода с традиционными решениями, которые предлагались языком программирования C. В частности, было интересно посмотреть, во что могут отображаться объектно-ориентированные конструкции, если их реализовать с применением "сишных" абстракций. Использование структур данных и указателей на функции позволило смоделировать конструкции, аналогичные тем, которые были прочитаны в книге Голуба [Golub-1996]. Схожий вариант моделирования ОО конструкций в стиле C позднее я описал на своем сайте в статье о "Разноруком программировании" [Legalov-dhp-2001] при сопоставлении особенностей процедурного и объектно-ориентированного подходов.
Далее, с опорой на распечатку книги Б. Страуструпа, пошло постепенное изучение основных приемов ООП с применением их в небольших программах, одной из которых была программа печати на матричном принтере текста в несколько колонок мелким шрифтом. Она использовалась для компактной печати различных текстов, включая и книгу Б. Страуструпа.
Следует отметить, что в этом первом издании шло прославление ОО подхода как фичи языка C++. Прогнозировалось светлое будущее ООП, что в целом оказалось верным.
Первоначальное представление об ООП сформировалось на основе общепринятых в то время описаний из книг, издаваемых на русском языке. До меня они дошли через Тимоти Бадда [Badd97], который, ссылаясь на Алана Кея, озвучил эти скрижали следующим образом:
-
Все является объектом.
-
Вычисления осуществляются путем взаимодействия (обмена данными) между объектами, при котором один объект требует, чтобы другой выполнил некое действие. Объекты взаимодействуют, посылая и получая сообщения. Сообщение - это запрос на выполнение действия, дополненный набором аргументов, которые могут понадобиться при выполнении действия.
-
Каждый объект имеет независимую память, которая состоит из других объектов.
-
Каждый объект является представителем класса, который выражает общие свойства объектов (таких, как целые числа или списки).
-
В классе задается поведение (функциональность) объекта. Тем самым все объекты, которые являются экземплярами одного класса, могут выполнять одни и те же действия.
-
Классы организованы в единую древовидную структуру с общим корнем, называемую иерархией наследования. Память и поведение, связанное с экземплярами определенного класса, автоматически доступны любому классу, расположенному ниже в иерархическом дереве.
Данные характеристики показывают, что ОО подход в целом определяет композиции программных объектов [Legalov-par-class-2018]. Алгоритмическая составляющая может быть любой, включая, например, императивный или функциональный стиль. Это отражено также в соответствующих языках императивного и функционального программирования, поддерживающих ООП.
Достаточно часто во многих книгах положения, декларируемые Аланом Кеем, подогревались утверждениями о том, что ОО подход более естественно описывает окружающий нас мир. Одной из таких являлась и книга Тимоти Бадда. Да и в недавно вышедших фолиантах, переживших не одно издание эта же мысль по-прежнему остается в силе [Weisfeld-2020].
Описанное классическое восприятие ОО подхода впоследствии отобразилось в ряде сделанных мною проектов, когда классы непосредственно отображали моделируемые объекты, автономно отвечая за те же функции, которые выполнялись в реальных системах. Одной из таких программ являлось рабочее место диспетчера по управлению тяговыми подстанциями трамвайно-троллейбусного управления. Основная идея системы заключалась в дистанционном управлении подстанциями, разбросанными по всему городу и обеспечивающими электропитанием троллейбусные линии,
На каждой такой подстанции сидели дежурные и следили за тем, чтобы оперативно информировать центральную диспетчерскую о сбоях, а также восстанавливать электропитание контактной сети, которая выходила из строя по различным причинам. В частности, могло возникнуть короткое замыкание после схода троллейбусных штанг с контактных проводов. При этом происходило автоматическое отключение линии. Тогда дежурный должен был вручную попытаться включить контактную сеть, а также сообщить в центральную диспетчерскую о произошедшей ситуации.
Предполагалась реализация дистанционного мониторинга подстанций через соответствующие контроллеры, передающие информацию о состоянии сети в диспетчерскую, а также управление включением в случае сбоев непосредственно из диспетчерской. Аналогичным образом должна была обрабатываться и другая информация, поступающая от каждой из подстанций. Например, сведения об обрыве сетей, которые также фиксировались оборудованием на подстанциях. В то время (первая половина 1990-х) контроллеры в разрабатываемой системе были сделаны на базе Спектрумов. Передача данных осуществлялась с использованием радиостанций. Рабочее место диспетчера было реализовано на базе ПК с MS DOS. Код писался на Borland C++ 3.1. Взаимодействие с радиостанцией осуществлялось через последовательный порт с использованием системы прерываний.
В ходе программирования каждая из подстанций формировалась как отдельный класс, наследующий от общего базового класса. Базовый класс подстанции частично имел чистые функции, но были и обработчики для общих ситуаций. С учетом уникальных особенностей аппаратуры на подстанциях, что определяло свои пакеты получаемых и передаваемых данных, в производных классах подстанций переопределялись виртуальные методы приема и передачи. Каждая подстанция имела свои подклассы для аппаратуры и отображения данных на экране дисплея. То есть, в системе непосредственно отображался окружающий мир в соответствии с рекламируемыми постулатами ОО программирования. Не было никаких делений подсистем на "модель-вид-контроллер".
Рисунок 1 – Окно для управления подстанциями, отображаемое в dosbox
Можно также отметить, что в целом никаких проблем с сопровождением и расширением системы не возникало (последнее было связано с добавлением новых подстанций с их дополнительными специфическими особенностями). Каждая новая подстанция добавлялась путем предварительного копипаста одного из производных классов с последующим изменением его методов в соответствии с необходимостью адаптировать под требуемую функциональность, аппаратуру и отображение всего этого. Возможно это рабочее место было не таким уж большим, чтобы испытывать затруднения в его сопровождении. Наверное сказывалось также и то, что оно разрабатывалось индивидуально, а взаимодействие происходило только с разработчиками аппаратуры и софта для подстанций. Система проработала в круглосуточном режиме более девяти лет.
Чем меня купил ОО подход? Своим методом обработки альтернативных конструкций, за счет использования ОО полиморфизма. В отличие от процедурного подхода, ориентированного на централизованный анализ альтернатив, можно было эволюционно добавлять новые программные объекты и настраивать их функциональность без изменения ранее написанного кода. Это оказалось удобным во многих ситуациях, с которыми приходилось сталкиваться. В целом подобное отношение к ОО программированию меня устраивало, так как большими коллективными проектами я не занимался.
Безоговорочная вера в ООП была поколеблена в 1994 году в ходе чтения лекций по ОО программированию на университетских курсах по повышению квалификации преподавателей. Я с воодушевлением рассказывал о возможностях наследования и полиморфизма, демонстрируя их на примере однонаправленных кольцевых списков, которые подсмотрел в книге Б. Страуструпа. Но в какой-то момент, при подготовке очередной лекции, я добрался до множественного полиморфизма, с которым ранее не встречался. В результате я "изобрел" двойную диспетчеризацию, реализовав набор альтернативных обработчиков различных чисел без явной проверки типа во время выполнения за счет использования полиморфизма и наследования. Много позднее появилась книга Джефа Элджера [Eldger-1999], из которой я узнал, что диспетчеризация в ООП была предложена задолго до меня. В книге говорилось об элегантности и эффективности этого приема. Однако, когда я реализовал мультиметод, то вместо восторгов испытал дискомфорт. Он был связан с тем, что любые добавления альтернативных классов приводили к модификации буквально всей ранее написанной иерархии классов за счет добавления в них не только новых мультиметодов, но и вспомогательных промежуточных методов, связывающих в уже написанных мультиметодах старые классы с вновь добавляемым. Гораздо позже я реализовал ряд эволюционных смешанных и чистых ОО решений [Legalov2002-OOP-MM-01], но всё это оказалось все равно менее эффективным и интересным по сравнению с процедурно-параметрическим полиморфизм, который в тот же период еще только моделировался[Legalov2002-PPP-MM-02].
Также мне не нравилось в ООП то, что любое добавление функциональности в виде нового метода вело к модификации соответствующего класса. Для мультиметода это связано также с добавлением вспомогательных методов, обеспечивающих цепочку диспетчеризации, что по сути перегружало класс "мусором". Следует отметить, что при реализации мультиметодов аналогичными недостатками страдают интерфейсы Go и типажи Rust. Преодолеть их нам удалось позднее в языках процедурно-параметрического программирования [o2m-site, ppc-site].
В ходе мировой эволюции ООП начали происходить существенные изменения, которые естественно повлияли на дальнейшую трансформацию моих взглядов в ходе изучения новых тенденций. В 1998 году один из моих аспирантов принес диск с книгой Банды четырех (GoF). То есть, до меня докатилось иное воззрение на мир объектов, которые уже перестали естественным образом описывать окружающий мир. Появились дополнительные конструкции и принципы проектирования, расколовшие понятие ООП на различные течения.
Рисунок 2 – Начальная страница книги по паттернам проектирования на CD
Вместо естественности отображения мира появилось стремление к удовлетворению различных критериев качества, основными из которых стали повторное использование кода и гибкое эволюционное расширение. Наследование реализации стало под запретом (возможно, во многих случаях обоснованно). Пошла пропаганда наследования интерфейсов. ОО подход перестал быть таким, каким определялся Аланом Кеем. Он стал размазанным по различным категориям и понятиям. Появилось много трактовок ООП, зачастую не связанных между собой. Была разрушена цельность восприятия парадигмы в угоду универсальности применения везде, где только можно и нельзя.
Впоследствии, с появлением и ростом популярности языка Java, позиционируемого как истинного ОО языка, Б.Страуструп начал говорить о будущем мультипарадигменного стиля [DannyKalev]. Его интервью, из-за совпадения в ряде идей, вдохновило меня к его переводу, а также написанию своего комментария [Legalov-review-2001]. Не хочу сказать, что только меня заинтересовала эта тема. Позднее в журнале Мир ПК появился "более официальный" и более качественный перевод [DannyKalev-pc-world]. Это было уже не первым сигналом к неоднозначному восприятию ООП, которое на заре его применения было относительно единым.
Мало кто сейчас может внятно, как в свое время Алан Кей, сформулировать, что такое ОО парадигма программирования. Но зато существует множество размытых трактовок и мнений по этому поводу. Что же произошло?
Исходная трактовка, сформулированная Аланом Кеем, позволяет взглянуть на ОО подход как на некоторое проблемно-ориентированное решение, удобное для эффективного представление автономных систем, обладающих определенным поведением и взаимодействующим с другими системами посредством передачи сообщений. Это позволяет наглядно описать хоть и не весь мир, но достаточно большую его часть, чтобы непосредственно использовать во многих программных проектах. Однако последующее стремление к универсальному использованию ООП, на мой взгляд, привело к тому, что при разработке ОО программ появилось множество дополнительных наслоений и промежуточных конструкций, отраженных в паттернах, принципах (SOLID) и прочих надстройках и пристройках. В результате использования где угодно ОО конструктив стал всё заменяющим, всеохватывающим, громоздким и неповоротливым. Основное достоинство ОО подхода - ОО полиморфизм. Оно обеспечило на первоначальных этапах требуемый эффект. Однако последующие навороты, оказались менее удобными и эффективными из-за избыточности промежуточных конструкций, вносимых при проектировании и кодировании .
В результате появились другие направления развития языков и стилей программирования, в рамках которых просматривается стремление упростить написание кода, избавив его во многих случаях от дополнительных этажерок. Среди них можно отметить и внедрение полиморфизма в процедурные языки. Это использование статической утиной типизации в Go и Rust. Близкий подход используется также и в языке Тривиль [Nedorya-2024-1, Nedorya-2024-2, Nedorya-2025-3, Nedorya-2025-4]. Предложенный и развиваемый мною процедурно-параметрический полиморфизм также рассматривается как средство, обеспечивающее формирование более простых по структуре процедурных программ[Legalov-2000-ppp].
Тенденция к расширению мультипарадигменных возможностей просматривается и в развитии современных ОО языков. В них включаются конструкции, нетипичные для ООП. В частности можно отметить добавление лямбда функций, обеспечивающих поддержку функционального программирования, средств поддержки генеративного программирования и метапрограммирования. Все это ведет к тому, что формируется следующая эпоха в написании софта, связанная с использованием мультипарадигменного стиля.
Накопленный опыт и поиски более гибких решений привели меня к мысли что ОО парадигма - это одна из предметно-ориентированных парадигм. Она удобна и эффективна для соответствующей предметной области. То есть там, где объекты непосредственно ложатся на предметную область. Но это только один из вариантов композиции программных объектов, обладающий своими достоинствами и недостатками (как и другие подходы). Ее применение в качестве универсальной и всеохватывающей панацеи вряд ли является целесообразным, так как ведет к многоэтажному бутерброду из промежуточных слоев, закрывающих зачастую ненужными объектами семантический разрыв между предметной областью и компьютерной программой. Отношения между предметами и процессами, отображаемыми на данные и код, в сочетании с требуемыми критериями качества зачастую гораздо богаче, чем то, что предлагается в ООП. Поэтому еще повторю сказанное в свое время Б. Страуструпом: "будущее за мультипарадигменным программированием".
Список используемых источников
Голуб А.И. C, C++. Правила программирования. М: Бином. 1996. - 272 с.
Легалов А.И.
Разнорукое программирование (2001).
Бадд Т. Объектно-ориентированное программирование в действии. /Пер. с англ. - СПб: Питер, 1997 - 464 с.
Легалов А.И.
О классификации парадигм программирования (2001).
Вайсфельд Мэтт. Объектно-ориентированный подход. 5-е межд. изд. - СПб.: Питер, 2020. - 256 с.
Элджер, Дж. C++: библиотека программиста.: Пер. с англ. / Дж. Элджер. – СПб.: ЗАО "Издательство Питер", 1999. – 320 с.
Легалов А.И. ООП, мультиметоды и пирамидальная эволюция. // Открытые системы. – 2002. – № 3. – С. 41-45.
Расширенная версия статьи: http://softcraft.ru/coding/evo/ (2002).
Легалов А.И.
Эволюция мультиметодов при процедурном подходе (2002).
Легалов А.И. Швец Д.А. Язык программирования О2М (2003-2004).
Легалов А.И., Косов П.В.
Процедурно-параметрическое расширение языка программирования C. Синтаксис и семантика (2024).
Дэнни Калев.
Интервью с Бьерном Страуструпом. Будущее за мультипарадигменным программированием (2001).
Легалов А.И.
Предлагаются альтернативные парадигмы программирования (2001).
Дэнни Калев. Будущее по Бьерну Страуструпу. Мир ПК, 2001, №5.
Недоря А.Е.
Разработка языка Тривиль. Первые шаги к семейству языков. Часть 1. - Цифровая экономика, №4(30), 2024.
Недоря А.Е.
Разработка языка Тривиль. Часть 2. - Цифровая экономика, №4(30), 2024.
Недоря А.Е.
Разработка языка Тривиль. Часть 3. Баланс. - Цифровая экономика, №1(31), 2025.
Недоря А.Е.
Разработка языка Тривиль. Часть 4. Реализация. - Цифровая экономика, №1(31), 2025.
Легалов А.И.
Процедурно-параметрическая парадигма программирования. Возможна ли альтернатива объектно-ориентированному стилю? / А. И. Легалов // Деп. рук. № 622-В00 Деп. в ВИНИТИ 13.03.2000. Красноярск. – 2000. – 43 с.
|