Всем привет.

Неделя статей на хабре посвященная ООП. Последняя статья вызвала у меня кучу эмоций и, к сожалению, очень плохих эмоций. Мне очень не понравилась статья. Почему? Потому что в ней передаются какие-то отрицательные эмоции об использовании ООП. Эмоции вызваны лишь тем, что человек не до конца понимает всю силу ООП и хочет убедить всех в том что ООП зло. Самое печальное что люди начинают прислушиваться и кидаться ужасными доводами, не имеющими ничего общего с действительностью. Я думаю что студентам такие статьи противопоказаны больше чем GoF, которых я бы давал как можно раньше. :)

Начнем.

Что такое ООП. ООП - это и ОО программирование и проектирование. Одно без другого бессмысленно чуть более чем полностью. Создано ООП для проектирования/программирования программных продуктов. Не для моделирования процессов. Не для проектирования протоколов, а именно для программных продуктов, для их реализации. Для упрощения системы, которая будет реализовывать протокол или бизнес-процесс или что-то еще.

Когда вы начинаете использовать ООП, первое что вы должны сделать - это начать использовать объектное мышление. Я уже когда-то говорил что это самая большая проблема ООП, научиться мыслить объектно очень сложно. И очень важно учиться это делать как можно раньше (GoF с аналогиями типа мост, конструктор, фасад очень в этом помогут). Используя объектное мышление, вы легко сможете проектировать сложные системы Используя объектное мышление вы легко можете решить любую задачу (очень важно что любую задачу проектирования/программирования, если ее в принципе можно решить абсолютно любую) оперируя объектами и взаимодействием между ними. Т.е. ООП без объектного мышления не позволит вам начать использовать всю силу и мощь ООП.

Пойдем дальше. Итак, нам важно мыслить объектно, для того, что бы найти нужные нам абстракции объектов для решения наших задач. Если аналогии и абстракции выбраны удачно, то мы видим очень четкую картину которая позволяет нам быстро разобраться в том, что же происходит в системе. И вот тут мы начинаем вспоминать про наследование и полиморфизм. Эти два инструмента нужны для удобного масштабирования системы без дублирования кода. Но сила этих механизмов зависит от того насколько удачные абстракции и аналогии вы выбрали. Если ваше объектное мышление не позволяет вам сформировать удобную декомпозицию объектов, то наследование и полиморфизм вам не помогут. Т.е. наследование и полиморфизм это ничто иное как инструменты, которые позволяют решить проблему масштабирования системы.

Как же эти инструменты работают? Да проще пареной репы, потому что это все основано на привычных нам вещах. Люблю простые примеры из жизни:

1. Наследование. Есть пекарь. Есть печь электрическая и газовая. Ваша задача смоделировать процесс приготовления пищи пекарем в каждой из печи. Решая задачу в лоб, у нас будет много дублирования кода из-за того, что сам процесс передачи пищи в печь и сама работа с печами идентичны для обеих печей. Но если мы включаем объектное мышление, и вспоминаем про инструмент наследование, то получаем примерно следующее (диаграмму лень рисовать, сорри):
Есть печь (абстрактная печь). У нее есть поведение - включить, выключить, увеличить или уменьшить температуру, положить чего-то, достать чего-то и состояние - температура в печи, включена или выключена. Это отличный пример абстрактного объекта в котором соблюдены принципы инкапсуляции (при реализации я их обязательно буду соблюдать). И есть пекарь, конкретный такой пекарь Иван. Он умеет работать с абстрактной печью. Т.е. смотреть температуру, включать выключать и т.д. вы поняли. Сила наследования в том, что нам не придется переписывать нашего Ивана для каждой из печей, будь то электро или газовая печь. Я думаю всем ясно почему? Получается что инструмент применен правильно.
2. Полиморфизм. Печи ведь по-разному работают. Газовая потребляет газ, электро печь - электричество. Используя полиморфизм мы легко меняем поведение в наследниках абстрактной печи.
3. Инкапсуляция. Основная фишка инкапсуляции в том, что я не должен знать, что происходит внутри моей печи. Допустим, я вызываю не метод включить печь, а меняю ее свойство включена на значение true. Что произойдет в этот момент? Если принцип инкапсуляции не соблюден, то я буду вынужден печи сказать начинай потреблять горючее, т.к. я тебя включил. Т.е. пекарь знает, что печь потребляет горючее, знает, как печь работает. Или, например, мы не можем установить температуру печи ниже или выше определенного уровня. Если не соблюдать принцип инкапсуляции, то мы должны будем говорить печи проверь-ка текущую температуру, пойдет те такая? Т.е. пекарь опять слишком много знает о печи. Геттеры и сеттеры это средства языка, которые помогут нам легко реализовать отслеживание изменений состояния. Все. Если геттеры и сеттеры пустые, значит так надо на моем уровне абстракции. Геттеры и сеттеры - не могут мешать реализации инкапсуляции, криво реализовать инкапсуляцию может проектировщик/программист.

В данном примере уровень абстракции выбран хорошо. Все занимаются своими делами, все три кита ООП работают во славу. Но стоит мне выбрать плохие абстракции, как начинается сущий кошмар. И даже есть стандарты чеклисты, которые помогут понять, хорошо ли вы выбрали абстракции и верна ли ваша декомпозиция в том ли направлении вы идете (SOLID).

Еще стали добавлять абстракцию, как еще один столп ООП. Я думаю, что это скорее верно, но уж очень попахивает КЭПом.

Высказывания про типизацию меня тоже зацепили. Дело в том, что никаких проблем в том, с кем вы сейчас работаете из наследников нет. Если на текущем уровне абстракции вам важно именно использовать печь, то вам не важно какая она. Вы получаете печь? Вы решаете свои задачи? То то и оно… Почему вы считаете что это динамическая типизация мне не понятно. Вы хотели печь? Берите. Вам нужна электрическая? Ну извините, газовая вам уже не подойдет.

Остальные примеры, которые были приведены в зацепившей меня статье, лишь примеры отвратительно выбранной абстракции и аналогии в рамках поставленной задачи. Точка.

Отдельно про DTO. DTO - это паттерн. Он позволяет создать объект, который передаст информацию другому слою, другой системе, короче куда-то чего-то передаст. Почему он не может быть рассмотрен мною как объект для меня вообще загадка. Где противоречие то? Является контейнером только? Ну и что?? Это же объект в рамках рассмотренной мною объектной модели на заданном уровне абстракции, где DTO - объект и часть декомпозиции.

Про языки тоже непонятно чего говорить. Я могу проектировать ПО используя объектный подход независимо от языка. Но если язык не реализует основные инструменты для работы с объектами, то мне будет очень сложно или невозможно реализовать спроектированную мною систему.

Еще говорят что некоторые вещи нельзя представить в виде объектов и их взаимодействия. Я уверен что это не так. Просто необходимо выбрать уровень абстракции верно. Будь то реализация протокола, слоя доступа к БД, подключения плагинов, менеджера задач, бизнес процесса, системы проектирования бизнес процессов т.е. все что угодно можно представить как объекты и их взаимодействие. Все можно реализовать как объекты и взаимодействие между ними. Хорошо это или плохо чаще всего зависит лишь от вашего умения мыслить объектно.

Резюмируя. Если вы не понимаете силу ООП, то скорее всего вам надо развивать объектное мышление.

P.S. В комментах к прошлой статье я явно много перегибал палку при обращении к некоторым людям. Приношу свои извинения.

Основные принципы и этапы объектно-ориентированного

программирования

В теории программирования ООП определяется как технология создания сложного программного обеспечения, которая основана на представлении программы в виде совокупности объектов , каждый из которых является экземпляром определенного типа (класса ), а классы образуют иерархию с

наследованием свойств .

Взаимодействие программных объектов в такой системе осуществляется путем передачи сообщений .

П р и м е ч а н и е. Такое представление программы впервые было использовано в языке имитационного моделирования сложных систем Simula, появившемся еще в 60-х годах.

Естественный для языков моделирования способ представления программы получил развитие в другом специализированном языке моделирования - языке Smalltalk (70-е годы), а затем был

Страница 2 из 51

Основные принципы ООП

использован в новых версиях универсальных языков программирования, таких как Pascal, С++,

Основное достоинство ООП - сокращение количества межмодульных вызовов и уменьшение объемов информации, передаваемой между модулями,

по сравнению с модульным программированием. Это достигается за счет более полной локализации данных и интегрирования их с подпрограммами обработки,

что позволяет вести практически независимую разработку отдельных частей

(объектов) программы.

Кроме этого, объектный подход предлагает новые технологические средства разработки, такие как наследование, полиморфизм, композиция, наполнение ,

позволяющие конструировать сложные объекты из более простых. В результате существенно увеличивается показатель повторного использования кодов,

появляется возможность создания библиотек объектов для различных применений, и разработчикам предоставляются дополнительные возможности создания систем повышенной сложности.

Основной недостаток ООП - некоторое снижение быстродействия за счет более сложной организации программной системы.

В основу ООП положены следующие п р и н ц и п ы : абстрагирование,

ограничение доступа, модульность, иерархичность, типизация, параллелизм,

устойчивость.

Рассмотрим, что представляет собой каждый принцип.

А б с т р а г и р о в а н и е - процесс выделения абстракций в предметной области задачи. Абстракция - совокупность существенных характеристик некоторого объекта, которые отличают его от всех других видов объектов и,

таким образом, четко определяют особенности данного объекта с точки зрения дальнейшего рассмотрения и анализа. В соответствии с определением применяемая абстракция реального предмета существенно зависит от решаемой задачи: в одном случае нас будет интересовать форма предмета, в другом вес, в

третьем - материалы, из которых он сделан, в четвертом - закон движения

Страница 3 из 51

Основные принципы ООП

предмета и т.д. Современный уровень абстракции предполагает объединение всех свойств абстракции (как касающихся состояния анализируемого объекта,

так и определяющих его поведение) в единую программную единицу некий

абстрактный тип (класс).

О г р а н и ч е н и е д о с т у п а - сокрытие отдельных элементов реализации абстракции, не затрагивающих существенных характеристик ее как целого.

Необходимость ограничения доступа предполагает разграничение двух частей в описании абстракции:

интерфейс - совокупность доступных извне элементов реализации абстракции (основные характеристики состояния и поведения);

реализация - совокупность недоступных извне элементов реализации абстракции (внутренняя организация абстракции и механизмы реализации ее поведения).

Ограничение доступа в ООП позволяет разработчику:

выполнять конструирование системы поэтапно, не отвлекаясь на особенности реализации используемых абстракций;

легко модифицировать реализацию отдельных объектов, что в правильно организованной системе не потребует изменения других объектов.

Сочетание объединения всех свойств предмета (составляющих его состояния и поведения) в единую абстракцию и ограничения доступа к реализации этих свойств получило название инкапсуляции.

М о д у л ь н о с т ь - принцип разработки программной системы,

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

Страница 4 из 51

Основные принципы ООП

модульного программирования, следование ему упрощает проектирование и

отладку программы.

И е р а р х и я - ранжированная или упорядоченная система абстракций.

Принцип иерархичности предполагает использование иерархий при разработке программных систем.

В ООП используются два вида иерархии.

Иерархия «целое/часть» - показывает, что некоторые абстракции включены

в рассматриваемую абстракцию как ее части, например, лампа состоит из цоколя, нити накаливания и колбы. Этот вариант иерархии используется в процессе разбиения системы на разных этапах проектирования (на логическом уровне - при декомпозиции предметной области на объекты, на физическом уровне - при декомпозиции системы на модули и при выделении отдельных процессов в мультипроцессной системе).

Иерархия «общее/частное» - показывает, что некоторая абстракция является частным случаем другой абстракции, например, « обеденный стол -

конкретный вид стола», а « столы - конкретный вид мебели». Используется при

разработке структуры классов, когда сложные классы строятся на базе более простых путем добавления к ним новых характеристик и, возможно, уточнения имеющихся.

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

наследование).

Т и п и з а ц и я - ограничение, накладываемое на свойства объектов и

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

объявляется тип, который определяет множество операций над

Страница 5 из 51

Основные принципы ООП

соответствующим программным объектом. Рассматриваемые далее языки программирования на основе Паскаля используют строгую, а на основе С -

среднюю степень типизации.

Использование принципа типизации обеспечивает:

раннее обнаружение ошибок, связанных с недопустимыми операциями над программными объектами (ошибки обнаруживаются на этапе компиляции программы при проверке допустимости выполнения данной операции над программным объектом);

упрощение документирования;

возможность генерации более эффективного кода.

Тип может связываться с программным объектом статически (тип объекта определен на этапе компиляции - раннее связывание) и динамически (тип объекта определяется только во время выполнения программы - позднее связывание). Реализация позднего связывания в языке программирования позволяет создавать переменные - указатели на объекты, принадлежащие различным классам (полиморфные объекты), что существенно расширяет возможности языка.

П а р а л л е л и з м - свойство нескольких абстракций одновременно находиться в активном состоянии, т.е. выполнять некоторые операции.

Существует целый ряд задач, решение которых требует одновременного выполнения некоторых последовательностей действий. К таким задачам,

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

Реальный параллелизм достигается только при реализации задач такого типа на многопроцессорных системах, когда имеется возможность выполнения каждого процесса отдельным процессором. Системы с одним процессором имитируют параллелизм за счет разделения времени процессора между задачами управления различными процессами. В зависимости от типа используемой операционной системы (одноили мультипрограммной)

Страница 6 из 51

Основные принципы ООП

разделение времени может выполняться либо разрабатываемой системой (как в

MS DOS), либо используемой ОС (как в системах Windows).

У с т о й ч и в о с т ь - свойство абстракции существовать во времени независимо от процесса, породившего данный программный объект, и/или в пространстве, перемещаясь из адресного пространства, в котором он был создан.

Различают:

∙ временные объекты, хранящие промежуточные результаты некоторых действий, например вычислений;

∙ локальные объекты, существующие внутри подпрограмм, время жизни которых исчисляется от вызова подпрограммы до ее завершения;

∙ глобальные объекты, существующие пока программа загружена в память;

∙ сохраняемые объекты, данные которых хранятся в файлах внешней памяти между сеансами работы программы.

Все указанные выше принципы в той или иной степени реализованы в различных версиях объектно-ориентированных языков.

Объектно-ориентированные языки программирования. Язык считается объектно-ориентированным, если в нем реализованы первые четыре из рассмотренных семи принципов.

Особое место занимают объектные модели Delphi и C++Builder. Эти модели обобщают опыт ООП для MS DOS и включают некоторые новые средства,

обеспечивающие эффективное создание более сложных систем. На базе этих моделей созданы визуальные среды для разработки приложений Windows.

Сложность программирования под Windows удалось существенно

снизить за счет создания специальных библиотек объектов, « спрятавших» многие элементы техники программирования.

Страница 7 из 51

Основные принципы ООП

Этапы разработки программных систем с использованием ООП.

Процесс разработки программного обеспечения с использованием ООП включает четыре этапа: анализ, проектирование, эволюция, модификация.

Рассмотрим эти этапы.

А н а л и з . Цель анализа - максимально полное описание задачи. На этом этапе выполняется анализ предметной области задачи, объектная декомпозиция разрабатываемой системы и определяются важнейшие особенности поведения объектов (описание абстракций). По результатам анализа разрабатывается структурная схема программного продукта, на которой показываются основные объекты и сообщения, передаваемые между ними, а также выполняется описание абстракций.

Проект ирование . Различают :

логическое проектирование, при котором принимаемые решения практически не зависят от условий эксплуатации (операционной системы и используемого оборудования);

физическое проектирование, при котором приходится принимать во внимание указанные факторы.

Логическое проектирование заключается в разработке структуры классов:

определяются поля для хранения составляющих состояния объектов и алгоритмы методов, реализующих аспекты поведения объектов. При этом используются рассмотренные выше приемы разработки классов (наследование,

композиция, наполнение, полиморфизм и т.д.). Результатом является иерархия или диаграмма классов, отражающие взаимосвязь классов, и описание классов.

Физическое проектирование включает объединение описаний классов в модули, выбор схемы их подключения (статическая или динамическая компоновка), определение способов взаимодействия с оборудованием, с

операционной системой и/или другим программным обеспечением (например,

базами данных, сетевыми программами), обеспечение синхронизации процессов для систем параллельной обработки и т.д.

Страница 8 из 51

Основные принципы ООП

Э в о л ю ц и я с и с т е м ы. Это процесс поэтапной реализации и

подключения классов к проекту. Процесс начинается с создания основной программы или проекта будущего программного продукта. Затем реализуются и подключаются классы, так чтобы создать грубый, но, по возможности,

работающий прототип будущей системы. Он тестируется и отлаживается.

Например, таким прототипом может служить система, включающая реализацию основного интерфейса программного продукта (передача сообщений в отсутствующую пока часть системы не выполняется). В результате мы получаем работоспособный прототип продукта, который может быть, например, показан заказчику для уточнения требований. Затем к системе подключается следующая группа классов, например, связанная с реализацией некоторого пункта меню.

Полученный вариант также тестируется и отлаживается, и так далее, до реализации всех возможностей системы.

Использование поэтапной реализации существенно упрощает тестирование и отладку программного продукта.

Модификация. Это процесс добавления новых функциональных возможностей или изменение существующих свойств системы. Как правило,

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

Изменение интерфейса - также не очень сложная задача, но ее решение может повлечь за собой необходимость согласования процессов взаимодействия объектов, что потребует изменений в других классах программы. Однако сокращение количества параметров в интерфейсной части по сравнению с модульным программированием существенно облегчает и этот процесс.

Простота модификации позволяет сравнительно легко адаптировать программные системы к изменяющимся условиям эксплуатации, что увеличивает время жизни систем, на разработку которых затрачиваются огромные временные и материальные ресурсы.

Страница 9 из 51

Основные принципы ООП

Особенностью ООП является то, что объект или группа объектов могут разрабатываться отдельно, и, следовательно, их проектирование может находиться на различных этапах. Например, интерфейсные классы уже реализованы, а структура классов предметной области еще только уточняется.

Обычно проектирование начинается, когда какой-либо фрагмент предметной области достаточно полно описан в процессе анализа.

Рассмотрение основных приемов объектного подхода начнем с объектной декомпозиции.

Объектная декомпозиция

Как уже упоминалось выше, при использовании технологии ООП решение представляется в виде результата взаимодействия отдельных функциональных элементов некоторой системы, имитирующей процессы,

происходящие в предметной области поставленной задачи.

В такой системе каждый функциональный элемент, получив некоторое входное воздействие (называемое сообщением) в процессе решения задачи,

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

Функциональные элементы системы, параметры и поведение которой определяются условием задачи, обладающие самостоятельным поведением

(т.е. « умеющие» выполнять некоторые действия, зависящие от полученных сообщений и состояния элемента), получили название объектов.

Процесс представления предметной области задачи в виде совокупности объектов, обменивающихся сообщениями, называется объектной декомпозицией.

Страница 10 из 51

Основные принципы ООП

Для того чтобы понять, о каких объектах и сообщениях идет речь при выполнении объектной декомпозиции в каждом конкретном случае, следует вспомнить, что первоначально объектный подход был предложен для разработки имитационных моделей поведения сложных систем. Набор объектов таких систем обычно определяется при анализе моделируемых процессов.

Пример. Объектная декомпозиция (имитационная модель

бензоколонки). Пусть нас интересует зависимость длины очереди к бензоколонке от количества заправочных мест, параметров обслуживания каждого заправочного места и интенсивности поступления заявок на заправку топливом (рассматриваем топливо одного типа).

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

Процесс работы бензоколонки с тремя заправочными местами можно представить в виде диаграммы.

Волею судьбы мне приходится читать спецкурс по паттернам проектирования в вузе. Спецкурс обязательный, поэтому, студенты попадают ко мне самые разные. Конечно, есть среди них и практикующие программисты. Но, к сожалению, большинство испытывают затруднения даже с пониманием основных терминов ООП.

Для этого я постарался на более-менее живых примерах объяснить базовые понятия ООП (класс, объект, интерфейс, абстракция, инкапсуляция, наследование и полиморфизм).

Первая часть, представленная ниже, посвящена классам, объектам и интерфейсам.
Вторая часть иллюстрирует инкапсуляцию, полиморфизм и наследование

Основные понятия ООП

Класс
Представьте себе, что вы проектируете автомобиль. Вы знаете, что автомобиль должен содержать двигатель, подвеску, две передних фары, 4 колеса, и т.д. Ещё вы знаете, что ваш автомобиль должен иметь возможность набирать и сбавлять скорость, совершать поворот и двигаться задним ходом. И, что самое главное, вы точно знаете, как взаимодействует двигатель и колёса, согласно каким законам движется распредвал и коленвал, а также как устроены дифференциалы. Вы уверены в своих знаниях и начинаете проектирование.

Вы описываете все запчасти, из которых состоит ваш автомобиль, а также то, каким образом эти запчасти взаимодействуют между собой. Кроме того, вы описываете, что должен сделать пользователь, чтобы машина затормозила, или включился дальний свет фар. Результатом вашей работы будет некоторый эскиз. Вы только что разработали то, что в ООП называется класс .

Класс – это способ описания сущности, определяющий состояние и поведение, зависящее от этого состояния, а также правила для взаимодействия с данной сущностью (контракт).

С точки зрения программирования класс можно рассматривать как набор данных (полей, атрибутов, членов класса) и функций для работы с ними (методов).

С точки зрения структуры программы, класс является сложным типом данных.

В нашем случае, класс будет отображать сущность – автомобиль. Атрибутами класса будут являться двигатель, подвеска, кузов, четыре колеса и т.д. Методами класса будет «открыть дверь», «нажать на педаль газа», а также «закачать порцию бензина из бензобака в двигатель». Первые два метода доступны для выполнения другим классам (в частности, классу «Водитель»). Последний описывает взаимодействия внутри класса и не доступен пользователю.

В дальнейшем, несмотря на то, что слово «пользователь» ассоциируется с пасьянсом «Косынка» и «Microsoft Word», мы будем называть пользователями тех программистов, которые используют ваш класс, включая вас самих. Человека, который является автором класса, мы будем называть разработчиком.

Объект
Вы отлично потрудились и машины, разработанные по вашим чертежам, сходят с конвейера. Вот они, стоят ровными рядами на заводском дворе. Каждая из них точно повторяет ваши чертежи. Все системы взаимодействуют именно так, как вы спроектировали. Но каждая машина уникальна. Они все имеют номер кузова и двигателя, но все эти номера разные, автомобили различаются цветом, а некоторые даже имеют литьё вместо штампованных дисков. Эти автомобили, по сути, являются объектами вашего класса.

Объект (экземпляр) – это отдельный представитель класса, имеющий конкретное состояние и поведение, полностью определяемое классом.

Говоря простым языком, объект имеет конкретные значения атрибутов и методы, работающие с этими значениями на основе правил, заданных в классе. В данном примере, если класс – это некоторый абстрактный автомобиль из «мира идей», то объект – это конкретный автомобиль, стоящий у вас под окнами.

Интерфейс
Когда мы подходим к автомату с кофе или садимся за руль, мы начинаем взаимодействие с ними. Обычно, взаимодействие происходит с помощью некоторого набора элементов: щель для приёмки монеток, кнопка выбора напитка и отсек выдачи стакана в кофейном автомате; руль, педали, рычаг коробки переключения передач в автомобиле. Всегда существует некоторый ограниченный набор элементов управления, с которыми мы можем взаимодействовать.

Интерфейс – это набор методов класса, доступных для использования другими классами.

Очевидно, что интерфейсом класса будет являться набор всех его публичных методов в совокупности с набором публичных атрибутов. По сути, интерфейс специфицирует класс, чётко определяя все возможные действия над ним.
Хорошим примером интерфейса может служить приборная панель автомобиля, которая позволяет вызвать такие методы, как увеличение скорости, торможение, поворот, переключение передач, включение фар, и т.п. То есть все действия, которые может осуществить другой класс (в нашем случае – водитель) при взаимодействии с автомобилем.

При описании интерфейса класса очень важно соблюсти баланс между гибкостью и простотой. Класс с простым интерфейсом будет легко использовать, но будут существовать задачи, которые с помощью него решить будет не под силу. В то же время, если интерфейс будет гибким, то, скорее всего, он будет состоять из достаточно сложных методов с большим количеством параметров, которые будут позволять делать очень многое, но использование его будет сопряжено с большими сложностями и риском совершить ошибку, что-то перепутав.

Примером простого интерфейса может служить машина с коробкой-автоматом. Освоить её управление очень быстро сможет любая блондинка, окончившая двухнедельные курсы вождения. С другой стороны, чтобы освоить управление современным пассажирским самолётом, необходимо несколько месяцев, а то и лет упорных тренировок. Не хотел бы я находиться на борту Боинга, которым управляет человек, имеющий двухнедельный лётный стаж. С другой стороны, вы никогда не заставите автомобиль подняться в воздух и перелететь из Москвы в Вашингтон.

Объе́ктно-ориенти́рованное программи́рование (ООП) - методология программирования , основанная на представлении программы в виде совокупности объектов , каждый из которых является экземпляром определённого класса , а классы образуют иерархию наследования .

Идеологически ООП - подход к программированию как к моделированию информационных объектов, решающий на новом уровне основную задачу структурного программирования : структурирование информации с точки зрения управляемости , что существенно улучшает управляемость самим процессом моделирования, что, в свою очередь, особенно важно при реализации крупных проектов.

Управляемость для иерархических систем предполагает минимизацию избыточности данных (аналогичную нормализации) и их целостность, поэтому созданное удобно управляемым - будет и удобно пониматься. Таким образом, через тактическую задачу управляемости решается стратегическая задача - транслировать понимание задачи программистом в наиболее удобную для дальнейшего использования форму.

Наиболее заметные отличия в проявлении показателей качества между языками разных видов:

  • В мейнстримных языках декларируемые принципы нацелены на повышение изначально низкого для императивного программирования коэффициента повторного использования кода . В полиморфно типизированных применение концепций ООП, напротив, означает очевидное его снижение из-за перехода от параметрического полиморфизма к ad-hoc-полиморфизму . В динамически типизированных языках (Smalltalk , Python , Ruby) эти принципы используются для логической организации программы, и их влияние на коэффициент повторного использования трудно спрогнозировать - он сильно зависит от дисциплины программиста. Например, в CLOS мультиметоды одновременно являются функциями первого класса , что позволяет рассматривать их одновременно и как связанно квантифицированные , и как обобщённые (истинно полиморфные).
  • Традиционные ОО-языки используют номинативную типизацию , то есть допустимость соиспользования объектов разных классов только при условии явного указания родственных отношений между классами. Для полиморфно типизированных языков характерна структурная типизация , то есть согласование классов между собой тем же механизмом, что и согласование числа 5 с типом int . Динамически типизированные языки также занимают здесь промежуточную позицию.

Обобщённое обоснование динамической диспетчеризации (включая множественную) в середине 1990-х годов построил Джузеппе Кастанья .

История

ООП возникло в результате развития идеологии процедурного программирования , где данные и подпрограммы (процедуры, функции) их обработки формально не связаны. Для дальнейшего развития объектно-ориентированного программирования часто большое значение имеют понятия события (так называемое событийно-ориентированное программирование) и компонента (компонентное программирование , КОП).

Взаимодействие объектов происходит посредством . Результатом дальнейшего развития ООП, по-видимому, будет агентно-ориентированое программирование , где агенты - независимые части кода на уровне выполнения. Взаимодействие агентов происходит посредством изменения среды , в которой они находятся.

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

Первым языком программирования, в котором были предложены основные понятия, впоследствии сложившиеся в парадигму, была Симула , но термин «объектная ориентированность» не использовался в контексте использования этого языка. В момент его появления в 1967 году в нём были предложены революционные идеи: объекты, классы, виртуальные методы и др., однако это всё не было воспринято современниками как нечто грандиозное. Фактически, Симула была «Алголом с классами», упрощающим выражение в процедурном программировании многих сложных концепций. Понятие класса в Симуле может быть полностью определено через композицию конструкций Алгола (то есть класс в Симуле - это нечто сложное, описываемое посредством примитивов).

Взгляд на программирование «под новым углом» (отличным от процедурного) предложили Алан Кэй и Дэн Ингаллс в языке Smalltalk . Здесь понятие класса стало основообразующей идеей для всех остальных конструкций языка (то есть класс в Смолтоке является примитивом, посредством которого описаны более сложные конструкции). Именно он стал первым широко распространённым объектно-ориентированным языком программирования .

В настоящее время количество прикладных языков программирования (список языков), реализующих объектно-ориентированную парадигму, является наибольшим по отношению к другим парадигмам. Наиболее распространённые в промышленности языки (С++, Delphi, C#, Java и др.) воплощают объектную модель Симулы. Примерами языков, опирающихся на модель Смолтока, являются Objective-C, Python, Ruby.

Определение ООП и его основные концепции

В центре ООП находится понятие объекта. Объект - это сущность, которой можно посылать сообщения и которая может на них реагировать, используя свои данные. Объект - это экземпляр класса. Данные объекта скрыты от остальной программы. Инкапсуляция включает в себя сокрытие (Но им не является!).

Наличие инкапсуляции достаточно для объектности языка программирования, но ещё не означает его объектной ориентированности - для этого требуется наличие наследования .

Но даже наличие инкапсуляции и наследования не делает язык программирования в полной мере объектным с точки зрения ООП. Основные преимущества ООП проявляются только в том случае, когда в языке программирования реализован полиморфизм подтипов - возможность единообразно обрабатывать объекты с различной реализацией при условии наличия общего интерфейса.

Сложности определения

ООП имеет уже более чем сорокалетнюю историю, но, несмотря на это, до сих пор не существует чёткого общепринятого определения данной технологии . Основные принципы, заложенные в первые объектные языки и системы, подверглись существенному изменению (или искажению) и дополнению при многочисленных реализациях последующего времени. Кроме того, примерно с середины 1980-х годов термин «объектно-ориентированный» стал модным , в результате с ним произошло то же самое, что несколько раньше с термином «структурный» (ставшим модным после распространения технологии структурного программирования) - его стали искусственно «прикреплять» к любым новым разработкам, чтобы обеспечить им привлекательность. Бьёрн Страуструп в 1988 году писал, что обоснование «объектной ориентированности» чего-либо, в большинстве случаев, сводится к некорректному силлогизму : «X - это хорошо. Объектная ориентированность - это хорошо. Следовательно , X является объектно-ориентированным».

Роджер Кинг аргументированно настаивал, что его кот является объектно-ориентированным. Кроме прочих своих достоинств, кот демонстрирует характерное поведение, реагирует на сообщения, наделён унаследованными реакциями и управляет своим, вполне независимым, внутренним состоянием.

Однако общность механизма обмена сообщениями имеет и другую сторону - «полноценная» передача сообщений требует дополнительных накладных расходов, что не всегда приемлемо. Поэтому во многих современных объектно-ориентированных языках программирования используется концепция «отправка сообщения как вызов метода» - объекты имеют доступные извне методы, вызовами которых и обеспечивается взаимодействие объектов. Данный подход реализован в огромном количестве языков программирования, в том числе C++ , Object Pascal , Java , Oberon-2 . Однако, это приводит к тому, что сообщения уже не являются самостоятельными объектами, и, как следствие, не имеют атрибутов, что сужает возможности программирования. Некоторые языки используют гибридное представление, демонстрируя преимущества одновременно обоих подходов - например, CLOS , Python .

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

Особенности реализации

Как уже говорилось выше, в современных объектно-ориентированных языках программирования каждый объект является значением, относящимся к определённому классу . Класс представляет собой объявленный программистом составной тип данных , имеющий в составе:

Поля данных Параметры объекта (конечно, не все, а только необходимые в программе), задающие его состояние (свойства объекта предметной области). Иногда поля данных объекта называют свойствами объекта, из-за чего возможна путаница. Фактически поля представляют собой значения (переменные, константы), объявленные как принадлежащие классу. Методы Процедуры и функции, связанные с классом. Они определяют действия, которые можно выполнять над объектом такого типа, и которые сам объект может выполнять.

Классы могут наследоваться друг от друга. Класс-потомок получает все поля и методы класса-родителя, но может дополнять их собственными либо переопределять уже имеющиеся. Большинство языков программирования поддерживает только единичное наследование (класс может иметь только один класс-родитель), лишь в некоторых допускается множественное наследование - порождение класса от двух или более классов-родителей. Множественное наследование создаёт целый ряд проблем, как логических, так и чисто реализационных, поэтому в полном объёме его поддержка не распространена. Вместо этого в 1990-е годы появилось и стало активно вводиться в объектно-ориентированные языки понятие интерфейса . Интерфейс - это класс без полей и без реализации, включающий только заголовки методов. Если некий класс наследует (или, как говорят, реализует) интерфейс, он должен реализовать все входящие в него методы. Использование интерфейсов предоставляет относительно дешёвую альтернативу множественному наследованию.

Взаимодействие объектов в абсолютном большинстве случаев обеспечивается вызовом ими методов друг друга.

Инкапсуляция обеспечивается следующими средствами:

Контроль доступа Поскольку методы класса могут быть как чисто внутренними, обеспечивающими логику функционирования объекта, так и внешними, с помощью которых взаимодействуют объекты, необходимо обеспечить скрытость первых при доступности извне вторых. Для этого в языки вводятся специальные синтаксические конструкции, явно задающие область видимости каждого члена класса. Традиционно это модификаторы public, protected и private, обозначающие, соответственно, открытые члены класса, члены класса, доступные внутри класса и из классов-потомков, и скрытые, доступные только внутри класса. Конкретная номенклатура модификаторов и их точный смысл различаются в разных языках. Методы доступа Поля класса в общем случае не должны быть доступны извне, поскольку такой доступ позволил бы произвольным образом менять внутреннее состояние объектов. Поэтому поля обычно объявляются скрытыми (либо язык в принципе не позволяет обращаться к полям класса извне), а для доступа к находящимся в полях данным используются специальные методы, называемые методами доступа. Такие методы либо возвращают значение того или иного поля, либо производят запись в это поле нового значения. При записи метод доступа может проконтролировать допустимость записываемого значения и, при необходимости, произвести другие манипуляции с данными объекта, чтобы они остались корректными (внутренне согласованными). Методы доступа называют ещё аксессорами (от англ. access - доступ), а по отдельности - геттерами (англ. get - чтение) и сеттерами (англ. set - запись) . Свойства объекта Псевдополя, доступные для чтения и/или записи. Свойства внешне выглядят как поля и используются аналогично доступным полям (с некоторыми исключениями), однако фактически при обращении к ним происходит вызов методов доступа. Таким образом, свойства можно рассматривать как «умные» поля данных, сопровождающие доступ к внутренним данным объекта какими-либо дополнительными действиями (например, когда изменение координаты объекта сопровождается его перерисовкой на новом месте). Свойства, по сути, не более чем синтаксический сахар , поскольку никаких новых возможностей они не добавляют, а лишь скрывают вызов методов доступа. Конкретная языковая реализация свойств может быть разной. Например, в объявление свойства непосредственно содержит код методов доступа, который вызывается только при работе со свойствами, то есть не требует отдельных методов доступа, доступных для непосредственного вызова. В Delphi объявление свойства содержит лишь имена методов доступа, которые должны вызываться при обращении к полю. Сами методы доступа представляют собой обычные методы с некоторыми дополнительными требованиями к сигнатуре .

Полиморфизм реализуется путём введения в язык правил, согласно которым переменной типа «класс» может быть присвоен объект любого класса-потомка её класса.

Проектирование программ в целом

ООП ориентировано на разработку крупных программных комплексов, разрабатываемых командой программистов (возможно, достаточно большой). Проектирование системы в целом, создание отдельных компонентов и их объединение в конечный продукт при этом часто выполняется разными людьми, и нет ни одного специалиста, который знал бы о проекте всё.

Объектно-ориентированное проектирование ориентируется на описание структуры проектируемой системы (приоритетно по отношению к описанию её поведения, в отличие от функционального программирования), то есть, фактически, в ответе на два основных вопроса:

  • Из каких частей состоит система ;
  • В чём состоит ответственность каждой из её частей .

Выделение частей производится таким образом, чтобы каждая имела минимальный по объёму и точно определённый набор выполняемых функций (обязанностей), и при этом взаимодействовала с другими частями как можно меньше.

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

Большое значение имеет правильное построение иерархии классов. Одна из известных проблем больших систем, построенных по ООП-технологии - так называемая проблема хрупкости базового класса . Она состоит в том, что на поздних этапах разработки, когда иерархия классов построена и на её основе разработано большое количество кода, оказывается трудно или даже невозможно внести какие-либо изменения в код базовых классов иерархии (от которых порождены все или многие работающие в системе классы). Даже если вносимые изменения не затронут интерфейс базового класса, изменение его поведения может непредсказуемым образом отразиться на классах-потомках. В случае крупной системы разработчик базового класса просто не в состоянии предугадать последствия изменений, он даже не знает о том, как именно базовый класс используется и от каких особенностей его поведения зависит корректность работы классов-потомков.

Различные ООП-методологии

Компонентное программирование - следующий этап развития ООП; прототип- и класс-ориентированное программирование - разные подходы к созданию программы, которые могут комбинироваться, имеющие свои преимущества и недостатки.

Компонентное программирование

Компонентно-ориентированное программирование - это своеобразная «надстройка» над ООП, набор правил и ограничений, направленных на построение крупных развивающихся программных систем с большим временем жизни. Программная система в этой методологии представляет собой набор компонентов с хорошо определёнными интерфейсами. Изменения в существующую систему вносятся путём создания новых компонентов в дополнение или в качестве замены ранее существующих. При создании новых компонентов на основе ранее созданных запрещено использование наследования реализации - новый компонент может наследовать лишь интерфейсы базового. Таким образом, компонентное программирование обходит проблему хрупкости базового класса.

Прототипное программирование

Прототипное программирование , сохранив часть черт ООП, отказалось от базовых понятий - класса и наследования.

  • Прототип - это объект-образец, по образу и подобию которого создаются другие объекты. Объекты-копии могут сохранять связь с родительским объектом, автоматически наследуя изменения в прототипе; эта особенность определяется в рамках конкретного языка .
  • Вместо механизма описания классов и порождения экземпляров, язык предоставляет механизм создания объекта (путём задания набора полей и методов, которые объект должен иметь) и механизм клонирования объектов.
  • Каждый вновь созданный объект является «экземпляром без класса». Каждый объект может стать прототипом - быть использован для создания нового объекта с помощью операции клонирования . После клонирования новый объект может быть изменён, в частности, дополнен новыми полями и методами.
  • Клонированный объект либо становится полной копией прототипа, хранящей все значения его полей и дублирующей его методы, либо сохраняет ссылку на прототип, не включая в себя клонированных полей и методов до тех пор, пока они не будут изменены. В последнем случае среда исполнения обеспечивает механизм делегирования - если при обращении к объекту он сам не содержит нужного метода или поля данных, вызов передаётся прототипу, от него, при необходимости - дальше по цепочке.

Класс-ориентированное программирование

Класс-ориентированное программирование - это программирование, сфокусированное на данных, причём данные и поведение неразрывно связаны между собой. Вместе данные и поведение представляют собой класс. Соответственно в языках, основанных на понятии «класс», все объекты разделены на два основных типа - классы и экземпляры. Класс определяет структуру и функциональность (поведение), одинаковую для всех экземпляров данного класса. Экземпляр является носителем данных - то есть обладает состоянием, меняющимся в соответствии с поведением, заданным классом. В класс-ориентированных языках новый экземпляр создаётся через вызов конструктора класса (возможно, с набором параметров). Получившийся экземпляр имеет структуру и поведение, жёстко заданные его классом.

Производительность объектных программ

Гради Буч указывает на следующие причины, приводящие к снижению производительности программ из-за использования объектно-ориентированных средств:

Динамическое связывание методов Обеспечение полиморфного поведения объектов приводит к необходимости связывать методы, вызываемые программой (то есть определять, какой конкретно метод будет вызываться) не на этапе компиляции, а в процессе исполнения программы, на что тратится дополнительное время. При этом реально динамическое связывание требуется не более чем для 20 % вызовов, но некоторые ООП-языки используют его постоянно. Значительная глубина абстракции ООП-разработка часто приводит к созданию «многослойных» приложений, где выполнение объектом требуемого действия сводится к множеству обращений к объектам более низкого уровня. В таком приложении происходит очень много вызовов методов и возвратов из методов, что, естественно, сказывается на производительности. Наследование «размывает» код Код, относящийся к «конечным» классам иерархии наследования, которые обычно и используются программой непосредственно, находится не только в самих этих классах, но и в их классах-предках. Относящиеся к одному классу методы фактически описываются в разных классах. Это приводит к двум неприятным моментам:

  • Снижается скорость трансляции, так как компоновщику приходится подгружать описания всех классов иерархии.
  • Снижается производительность программы в системе со страничной памятью - поскольку методы одного класса физически находятся в разных местах кода, далеко друг от друга, при работе фрагментов программы, активно обращающихся к унаследованным методам, система вынуждена производить частые переключения страниц.
Инкапсуляция снижает скорость доступа к данным Запрет на прямой доступ к полям класса извне приводит к необходимости создания и использования методов доступа. И написание, и компиляция, и исполнение методов доступа сопряжены с дополнительными расходами. Динамическое создание и уничтожение объектов Динамически создаваемые объекты, как правило, размещаются в куче , что менее эффективно, чем размещение их на стеке и, тем более, статическое выделение памяти под них на этапе компиляции.

Несмотря на отмеченные недостатки, Буч утверждает, что выгоды от использования ООП более весомы. Кроме того, повышение производительности за счёт лучшей организации ООП-кода, по его словам, в некоторых случаях компенсирует дополнительные накладные расходы на организацию функционирования программы. Можно также заметить, что многие эффекты снижения производительности могут сглаживаться или даже полностью устраняться за счёт качественной оптимизации кода компилятором. Например, упомянутое выше снижение скорости доступа к полям класса из-за использования методов доступа устраняется, если компилятор вместо вызова метода доступа использует инлайн-подстановку (современные компиляторы делают это вполне уверенно).

Критика ООП

Несмотря на отдельные критические замечания в адрес ООП, в настоящее время именно эта парадигма используется в подавляющем большинстве промышленных проектов. Однако нельзя считать, что ООП является наилучшей из методик программирования во всех случаях.

Критические высказывания в адрес ООП:

  • Было показано отсутствие значимой разницы в продуктивности разработки программного обеспечения между ООП и процедурным подходом .
  • Кристофер Дэйт указывает на невозможность сравнения ООП и других технологий во многом из-за отсутствия строгого и общепризнанного определения ООП .
  • Александр Степанов в одном из своих интервью указывал, что ООП «методологически неправильно» и что «…ООП практически такая же мистификация , как и искусственный интеллект …» .
  • Фредерик Брукс указывает, что наиболее сложной частью создания программного обеспечения является «…спецификация, дизайн и тестирование концептуальных конструкций, а отнюдь не работа по выражению этих концептуальных конструкций…». ООП (наряду с такими технологиями как искусственный интеллект, верификация программ, автоматическое программирование, графическое программирование , экспертные системы и др.), по его мнению, не является «серебряной пулей», которая могла бы на порядок величины снизить сложность разработки программных систем. Согласно Бруксу, «…ООП позволяет сократить только привнесённую сложность в выражение дизайна. Дизайн остаётся сложным по своей природе…» .
  • Эдсгер Дейкстра указывал: «…то, о чём общество в большинстве случаев просит - это эликсир от всех болезней. Естественно, „эликсир“ имеет очень впечатляющие названия, иначе будет очень трудно что-то продать: „Структурный анализ и Дизайн“, „Программная инженерия“, „Модели зрелости“, „Управляющие информационные системы“ (Management Information Systems), „Интегрированные среды поддержки проектов“, „Объектная ориентированность“, „Реинжиниринг бизнес-процессов “…» .
  • Никлаус Вирт считает, что ООП - не более чем тривиальная надстройка над структурным программированием [ ] , и преувеличение её значимости, выражающееся, в том числе, во включении в языки программирования всё новых модных «объектно-ориентированных» средств, вредит качеству разрабатываемого программного обеспечения.
  • Патрик Киллелиа в своей книге «Тюнинг веб-сервера» писал: «…ООП предоставляет вам множество способов замедлить работу ваших программ…».
  • Известная обзорная статья проблем современного ООП-программирования перечисляет некоторые типичные проблемы ООП [ ] .
  • В программистском фольклоре получила широкое распространение критика объектно-ориентированного подхода в сравнении с функциональным подходом с использованием метафоры «Королевства Существительных » из эссе Стива Йегги .

Если попытаться классифицировать критические высказывания в адрес ООП, можно выделить несколько аспектов критики данного подхода к программированию.

Критика рекламы ООП Критикуется явно высказываемое или подразумеваемое в работах некоторых пропагандистов ООП, а также в рекламных материалах «объектно-ориентированных» средств разработки представление об объектном программировании как о некоем всемогущем подходе, который магическим образом устраняет сложность программирования. Как замечали многие, в том числе упомянутые выше Брукс и Дейкстра, «серебряной пули не существует» - независимо от того, какой парадигмы программирования придерживается разработчик, создание нетривиальной сложной программной системы всегда сопряжено со значительными затратами интеллектуальных ресурсов и времени. Из наиболее квалифицированных специалистов в области ООП никто, как правило, не отрицает справедливость критики этого типа. Оспаривание эффективности разработки методами ООП Критики оспаривают тезис о том, что разработка объектно-ориентированных программ требует меньше ресурсов или приводит к созданию более качественного ПО. Проводится сравнение затрат на разработку разными методами, на основании которого делается вывод об отсутствии у ООП преимуществ в данном направлении. Учитывая крайнюю сложность объективного сравнения различных разработок, подобные сопоставления, как минимум, спорны. С другой стороны, получается, что ровно так же спорны и утверждения об эффективности ООП. Производительность объектно-ориентированных программ Указывается на то, что целый ряд «врождённых особенностей» ООП-технологии делает построенные на её основе программы технически менее эффективными, по сравнению с аналогичными необъектными программами. Не отрицая действительно имеющихся дополнительных накладных расходов на организацию работы ООП-программ (см. раздел «Производительность» выше), нужно, однако, отметить, что значение снижения производительности часто преувеличивается критиками. В современных условиях, когда технические возможности компьютеров чрезвычайно велики и постоянно растут, для большинства прикладных программ техническая эффективность оказывается менее существенна, чем функциональность, скорость разработки и сопровождаемость. Лишь для некоторого, очень ограниченного класса программ (ПО встроенных систем, драйверы устройств, низкоуровневая часть системного ПО, научное ПО) производительность остаётся критическим фактором. Критика отдельных технологических решений в ООП-языках и библиотеках Эта критика многочисленна, но затрагивает она не ООП как таковое, а приемлемость и применимость в конкретных случаях тех или иных реализаций её механизмов. Одним из излюбленных объектов критики является язык C++, входящий в число наиболее распространённых промышленных ООП-языков.

Объектно-ориентированные языки

Многие современные языки специально созданы для облегчения объектно-ориентированного программирования. Однако следует отметить, что можно применять техники ООП и для не-объектно-ориентированного языка и наоборот, применение объектно-ориентированного языка вовсе не означает, что код автоматически становится объектно-ориентированным.

Объектно-ориентированное программирование (ООП) позволяет разложить проблему на составные части, каждая из которых становится самостоятельным объектом. Каждый из объектов содержит свой собственный код и данные, которые относятся к этому объекту.

Любая программа, написанная на языке ООП, отражает в своих данных состояние физических предметов либо абстрактных понятий – объектов программирования, для работы, с которыми она предназначена.

Все данные об объекте программирования и его связях с другими объектами можно объединить в одну структурированную переменную. В первом приближении ее можно назвать объектом.

С объектом связывается набор действий, иначе называемых методами . С точки зрения языка программирования набор действий или методов – это функции, получающие в качестве обязательного параметра указатель на объект и выполняющие определенные действия с данными объекта программирования. Технология ООП запрещает работать с объектом иначе, чем через методы, таким образом, внутренняя структура объекта скрыта от внешнего пользователя.

Описание множества однотипных объектов называется классом .
Объект – это структурированная переменная, содержащая всю информацию о некотором физическом предмете или реализуемом в программе понятии.

Класс – это описание множества объектов программирования (объектов) и выполняемых над ними действий.

Класс можно сравнить с чертежом, согласно которому создаются объекты. Обычно классы разрабатывают таким образом, чтобы их объекты соответствовали объектам предметной области решаемой задачи.

Основные понятия объектно-ориентированного программирования

Любая функция в программе представляет собой метод для объекта некоторого класса.

Класс должен формироваться в программе естественным образом, как только в ней возникает необходимость описания новых объектов программирования. Каждый новый шаг в разработке алгоритма должен представлять собой разработку нового класса на основе уже существующих.

Вся программа в таком виде представляет собой объект некоторого класса с единственным методом run (выполнить).

Программирование «от класса к классу» включает в себя ряд новых понятий. Основными понятиями ООП являются

  • инкапсуляция;
  • наследование;
  • полиморфизм.

Инкапсуляция данных (от «капсула») – это механизм, который объединяет данные и код, манипулирующий с этими данными, а также защищает и то, и другое от внешнего вмешательства или неправильного использования. В ООП код и данные могут быть объединены вместе (в так называемый «черный ящик») при создании объекта.

Внутри объекта коды и данные могут быть закрытыми или открытыми.

Закрытые коды или данные доступны только для других частей того же самого объекта и, соответственно, недоступны для тех частей программы, которые существуют вне объекта.

Открытые коды и данные, напротив, доступны для всех частей программы, в том числе и для других частей того же самого объекта.

Наследование . Новый, или производный класс может быть определен на основе уже имеющегося, или базового класса.

При этом новый класс сохраняет все свойства старого: данные объекта базового класса включаются в данные объекта производного, а методы базового класса могут быть вызваны для объекта производного класса, причем они будут выполняться над данными включенного в него объекта базового класса.

Иначе говоря, новый класс наследует как данные старого класса, так и методы их обработки.

Если объект наследует свои свойства от одного родителя, то говорят об одиночном наследовании . Если объект наследует данные и методы от нескольких базовых классов, то говорят о множественном наследовании .

Пример наследования – определение структуры, отдельный член которой является ранее определенной структурой.

Полиморфизм – это свойство, которое позволяет один и тот же идентификатор (одно и то же имя) использовать для решения двух и более схожих, но технически разных задач.

Целью полиморфизма, применительно к ООП, является использование одного имени для задания действий, общих для ряда классов объектов. Такой полиморфизм основывается на возможности включения в данные объекта также и информации о методах их обработки (в виде указателей на функции).

Будучи доступным в некоторой точке программы, объект, даже при отсутствии полной информации о его типе, всегда может корректно вызвать свойственные ему методы.
Полиморфная функция – это семейство функций с одним и тем же именем, но выполняющие различные действия в зависимости от условий вызова.

Например, нахождение абсолютной величины в языке Си требует трех разных функций с разными именами.