Разное

Концепции объектно ориентированного программирования: НОУ ИНТУИТ | Лекция | Основы объектно-ориентированного программирования

Содержание

Концепции объектно-ориентированного программирования — Студопедия

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

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

Основным понятием ООП является объект или класс в C++, который можно рас­сматривать с двух позиций. Во-первых, с позиции предметной области: класс соответ­ствует определенному характерному объекту этой области. Во-вторых, с позиции технологии программирования, реализующей это соответствие: «класс» в ООП — это определенная программная структура, которая обладает тремя важней­шими свойствами:



— инкапсуляции;

— наследования;

— полиморфизма.

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

Объекты и классы.

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

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


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

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

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

Инкапсуляция свойств объектов.

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

В C++ данные класса и объекта называются элементами данных или полями,а функции — методами или элементами-функциями.

Доступ к полям и методам объекта осуществляется через имя объекта и соот­ветствующие имена полей и методов при помощи операций выбора «.» и «->». Это позволяет в максимальной степени изолировать содержание объекта от внеш­него окружения, т. е. ограничить и наглядно контролировать доступ к элементам объекта. В результате замена или модификация полей и методов, инкапсулиро­ванных в объект, как правило, не влечет за собой плохо контролируемых послед­ствий для программы в целом. При необходимости указания имени объекта в теле описания этого объекта в C++ используется зарезервированное слово this,, которое в рамках объекта является специальным синонимом имени объекта — указателем на объект.

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

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

А теперь определение, которое точно определяет суть инкапсуляции:

Переменные состояния объекта скрыты от внешнего мира. Изменение состояния объекта(его переменных) возможно ТОЛЬКО с помощью его методов(операций).

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

Это существенно ограничивает возможность введения объекта в недопустимое состояние и несанкционированное разрушение этого объекта.

Для иллюстрации приведенного выше постулата рассмотрим пример.

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

Для того, чтобы починить машину не причинив себе и самой машине вреда необходимо пригласить квалифицированных авто-слесарей, причем каждый из которых отлично разбирается только в определенной части Вашей машины. Если Вы скажете, что у Вас не горит лампочка подсветки в салоне, то замену лампочки проведет специалист по электрооборудованию автомобилей. Аналогично и в нашем объекте. Есть «мастера» — методы, которые «специализируются» в определенных областях, но свою область они знают. А самое главное, они знают как можно изменить состояние объекта так, чтобы не повредить его. Описанный постулат отражает простую житейскую мудрость: не знаешь, не представляешь как что-то сделать — попроси это сделать того, кто знает как это правильно надо сделать. К сожалению, все мы на каждом шагу пренебрегаем этим правилом. В ООП мы это правило определяем как закон: «Объект не приемлет дилетантов. Только специалисты могут как-либо изменять состояние объекта.» Вы можете сказать, что этот принцип далеко не новость в программировании.

Именование классов, элементов данных и методов имеет большое значение в ООП. Названия должны либо совпадать с названиями, использующимися в предметной области, либо ясно отражать смысл или назначение (функциональность) именуемого класса, поля или метода. При этом не следует бояться длинных имен — затраты на написание окупятся при отладке и сопровождении продукта. Текст подобной программы становится понятным без особых комментари­ев. Дополнительным средством доступа к данным и методам является описание элементов классов с помощью спецификаторов private, protected и public, которые определяют три соответствующих уровня доступа к компонентам класса: частные, защищенный и общедоступный.

Для расширения доступа к элементам данных, имеющим атрибуты private или protected, в классе можно реализовать с атрибутом public специальные методы досту­па к собственным и защищенным элементам данных.

Методы в классе могут быть объявлены как дружественные (friend) или виртуальные (virtual). Иногда встречается объявление перегружаемых (overload) функций.

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

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

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

Наследование есть свойство классов порождать своих потомков и наследо­вать свойства (элементы данных и методы) своих родителей. Класс-потомок автоматически наследует от родителя все элементы данных и методы, а также может содержать новые элементы данных и методы и даже заменять (перекры­вать, переопределять) методы родителя или модифицировать (дополнять) их.

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

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

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

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

Наследование в ООП позволяет адекватно отражать родственные отношения объектов предметной области. Если класс В обладает всеми свойствами клас­са А и еще имеет дополнительные свойства, то класс А называется базовым (родительским), а класс В называется наследником класса А. В C++ возможно одиночное (с одним родителем) и множественное (с несколькими родителями) наследование.

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

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

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

Примеры родственных классов: Координаты на экране -> Цветная точка -> Пря­мая -> Прямоугольник. Здесь направление стрелки указывает порядок наследования свойств классов.

При указании базового (родительского) класса в описании класса в С++ требуется указать ключевое слово public. Указание этого ключевого слова позволит получить свободный доступ ко всем методам класса, как если бы они были описаны в самом производном классе. В противном же случае, мы не сможем получить доступ к методам родительского класса.

Пример описания наследования классов на С++:

class A

{

. . . . .

}

class B : public A

{

. . . . .

}

Я не знаю ООП / Хабр

Я не умею программировать на объектно-ориентированных языках. Не научился. После 5 лет промышленного программирования на Java я всё ещё не знаю, как создать хорошую систему в объектно-ориентированном стиле. Просто не понимаю.

Я пытался научиться, честно. Я изучал паттерны, читал код open source проектов, пытался строить в голове стройные концепции, но так и не понял принципы создания качественных объектно-ориентированных программ. Возможно кто-то другой их понял, но не я.

И вот несколько вещей, которые вызывают у меня непонимание.

Я не знаю, что такое ООП

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

Принято считать, что объектно-ориентированное программирование строится на 4 основных принципах (когда я был мал, их было всего 3, но ведь тогда и деревья были большими). Эти принципы:

  • Абстракция
  • Инкапсуляция
  • Наследование
  • Полиморфизм

Смахивает на свод правил, не так ли? Значит вот оно, те самые правила, которым нужно следовать в 95% случаев? Хмм, давайте посмотрим поближе.

Абстракция

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

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

Во-вторых, абстракции в программировании были всегда, начиная с записей Ады Лавлейс, которую принято считать первым в истории программистом. С тех пор люди бесперерывно создавали в своих программах абстракции, зачастую имея для этого лишь простейшие средства. Так, Абельсон и Сассман в своей небезызвестной книге описывают, как создать систему решения уравнений с поддержкой комплексных чисел и даже полиномов, имея на вооружении только процедуры и связные списки. Так какие же дополнительные средства абстрагирования несёт в себе ООП? Понятия не имею. Выделение кода в подпрограммы? Это умеет любой высокоуровневый язык. Объединение подпрограмм в одном месте? Для этого достаточно модулей. Типизация? Она была задолго до ООП. Пример с системой решения уравнений хорошо показывает, что построение уровней абстракции не столько зависит от средств языка, сколько от способностей программиста.

Инкапсуляция

Главный козырь инкапсуляции в сокрытии реализации. Клиентский код видит только интерфейс, и только на него может рассчитывать. Это развязывает руки разработчикам, которые могут решить изменить реализацию. И это действительно круто. Но вопрос опять же в том, причём тут ООП? Все вышеперечисленные парадигмы подразумевают сокрытие реализации. Программируя на C вы выделяете интерфейс в header-файлы, Oberon позволяет делать поля и методы локальными для модуля, наконец, абстракция во многих языках строится просто посредствам подпрограмм, которые также инкапсулируют реализацию. Более того, объектно-ориентированные языки сами зачастую нарушают правило инкапсуляции, предоставляя доступ к данным через специальные методы — getters и setters в Java, properties в C# и т.д. (В комментариях выяснили, что некоторые объекты в языках программирования не являются объектами с точки зрения ООП: data transfer objects отвечают исключительно за перенос данных, и поэтому не являются полноценными сущностями ООП, и, следовательно, для них нет необходимости сохранять инкапсуляцию. С другой стороны, методы доступа лучше сохранять для поддержания гибкости архитектуры. Вот так всё непросто.) Более того, некоторые объектно-ориентированные языки, такие как Python, вообще не пытаются что-то скрыть, а расчитывают исключительно на разумность разработчиков, использующих этот код.

Наследование

Наследование — это одна из немногих новых вещей, которые действительно вышли на сцену благодаря ООП. Нет, объектно-ориентированные языки не создали новую идею — наследование вполне можно реализовать и в любой другой парадигме — однако ООП впервые вывело эту концепцию на уровень самого языка. Очевидны и плюсы наследования: когда вас почти устраивает какой-то класс, вы можете создать потомка и переопределить какую-то часть его функциональности. В языках, поддерживающих множественное наследование, таких как C++ или Scala (в последней — за счёт traits), появляется ещё один вариант использования — mixins, небольшие классы, позволяющие «примешивать» функциональность к новому классу, не копируя код.

Значит, вот оно — то, что выделяет ООП как парадигму среди других? Хмм… если так, то почему мы так редко используем его в реальном коде? Помните, я говорил про 95% кода, подчиняющихся правилам доминирующей парадигмы? Я ведь не шутил. В функцинальном программировании не меньше 95% кода использует неизменяемые данные и функции без side-эффектов. В модульном практически весь код логично расфасован по модулям. Преверженцы структурного программирования, следуя заветам Дейкстры, стараются разбивать все части программы на небольшие части. Наследование используется гораздо реже. Может быть в 10% кода, может быть в 50%, в отдельных случаях (например, при наследовании от классов фреймворка) — в 70%, но не больше. Потому что в большинстве ситуаций это просто не нужно.

Более того, наследование опасно для хорошего дизайна. Настолько опасно, что Банда Четырех (казалось бы, проповедники ООП) в своей книге рекомендуют при возможности заменять его на делегирование. Наследование в том виде, в котором оно существует в популярных ныне языках ведёт к хрупкому дизайну. Унаследовавшись от одного предка, класс уже не может наследоваться от других. Изменение предка так же становится опасным. Существуют, конечно, модификаторы private/protected, но и они требуют неслабых экстрасенсорных способностей для угадывания, как класс может измениться и как его может использовать клиентский код. Наследование настолько опасно и неудобно, что крупные фреймворки (такие как Spring и EJB в Java) отказываются от них, переходя на другие, не объектно-ориентированные средства (например, метапрограммирование). Последствия настолько непредсказуемы, что некоторые библиотеки (такие как Guava) прописывает своим классам модификаторы, запрещающие наследование, а в новом языке Go было решено вообще отказаться от иерархии наследования.

Полиморфизм

Пожалуй, полиморфизм — это лучшее, что есть в объектно-ориентированном программировании. Благодаря полиморфизму объект типа Person при выводе выглядит как «Шандоркин Адам Имполитович», а объект типа Point — как «[84.23 12.61]». Именно он позволяет написать «Mat1 * Mat2» и получить произведение матриц, аналогично произведению обычных чисел. Без него не получилось бы и считывать данные из входного потока, не заботясь о том, приходят они из сети, файла или строки в памяти. Везде, где есть интерфейсы, подразумевается и полиморфизм.

Мне правда нравится полиморфизм. Поэтому я даже не стану говорить о его проблемах в мейнстримовых языках. Я также промолчу про узость подхода диспетчеризации только по типу, и про то, как это могло бы быть сделано. В большинстве случаев он работает как надо, а это уже неплохо. Вопрос в другом: является ли полиморфизм тем самым принципом, отличающим ООП от других парадигм? Если бы вы спросили меня (а раз уж вы читаете этот текст, значит, можно считать, что спросили), я бы ответил «нет». И причина всё в тех же процентах использования в коде. Возможно, интерфейсы и полиморфные методы встречаются немного чаще наследования. Но сравните количество строк кода, занимаемое ими, с количеством строк, написанных в обычном процедурном стиле — последних всегда больше. Глядя на языки, поощряющие такой стиль программирования, я не могу назвать их полиморфными. Языки с поддержкой полиморфизма — да, так нормально. Но не полиморфные языки.

(Впрочем, это моё мнение. Вы всегда можете не согласиться.)

Итак, абстракция, инкапсуляция, наследование и полиморфизм — всё это есть в ООП, но ничто из этого не является его неотъемлемым атрибутом. Тогда что такое ООП? Есть мнение, что суть объектно-ориентированного программирования лежит в, собственно, объектах (звучит вполне логично) и классах. Именно идея объединения кода и данных, а также мысль о том, что объекты в программе отражают сущности реального мира. К этому мнению мы ещё вернёмся, но для начала расставим некоторые точки над i.

Чьё ООП круче?

Из предыдущей части видно, что языки программирования могут сильно отличаться по способу реализации объектно-ориентированного программирования. Если взять совокупность всех реализаций ООП во всех языках, то вероятнее всего вы не найдёте вообще ни одной общей для всех черты. Чтобы как-то ограничить этот зоопарк и внести ясность в рассуждения, я остановлюсь только одной группе — чисто объекто-ориентированные языки, а именно Java и C#. Термин «чисто объектно-ориентированный» в данном случае означает, что язык не поддерживает другие парадигмы или реализует их через всё то же ООП. Python или Ruby, например, не буду являться чистыми, т.к. вы вполне можете написать полноценную программу на них без единого объявления класса.

Чтобы лучше понять суть ООП в Java и C#, пробежимся по примерам реализации этой парадигмы в других языках.

Smalltalk. В отличие от своих современных коллег, этот язык имел динамическую типизацию и использовал message-passing style для реализации ООП. Вместо вызовов методов объекты посылали друг другу сообщения, а если получатель не мог обработать то, что пришло, он просто пересылал сообщение кому-то ещё.

Common Lisp. Изначально CL придерживался такой же парадигмы. Затем разработчики решили, что писать `(send obj ‘some-message)` — это слишком долго, и преобразовали нотацию в вызов метода — `(some-method obj)`. На сегодняшний день Common Lisp имеет развитую систему объектно-ориентированного программирования (CLOS) с поддержкой множественного наследования, мультиметодов и метаклассов. Отличительной чертой является то, что ООП в CL крутится не вокруг объектов, а вокруг обобщённых функций.

Clojure. Clojure имеет целых 2 системы объектно-ориентированного программирования — одну, унаследованную от Java, и вторую, основанную на мультиметодах и более похожую на CLOS.

R. Этот язык для статистического анализа данных также имеет 2 системы объектно-ориентированного программирования — S3 и S4. Обе унаследованы от языка S (что не удивительно, учитывая, что R — это open source реализация коммерческого S). S4 по большей части соотвествует реализациям ООП в современных мейнстримовых языках. S3 является более легковесным вариантом, элементарно реализуемым средствами самого языка: создаётся одна общая функция, диспетчеризирующая запросы по атрибуту «class» полученного объекта.

JavaScript. По идеологии похож на Smalltalk, хотя и использует другой синтаксис. Вместо наследования использует прототипирование: если искомого свойства или вызванного метода в самом объекте нет, то запрос передаётся объекту-прототипу (свойство prototype всех объектов JavaScript). Интересным является факт, что поведение всех объектов класса можно поменять, заменив один из методов прототипа (очень красиво, например, выглядит добавление метода `.toBASE64` для класса строки).

Python. В целом придерживается той же концепции, что и мейнcтримовые языки, но кроме этого поддерживает передачу поиска атрибута другому объекту, как в JavaScript или Smalltalk.

Haskell. В Haskell вообще нет состояния, а значит и объектов в обычном понимании. Тем не менее, своеобразное ООП там всё-таки есть: типы данных (types) могут принадлежать одному или более классам типов (type classes). Например, практически все типы в Haskell состоят в классе Eq (отвечает за операции сравнения 2-х объектов), а все числа дополнительно в классах Num (операции над числами) и Ord (операции <, <=, >=, >). В менстримовых языках типам соответствуют классы (данных), а классам типов — интерфейсы.

Stateful или Stateless?

Но вернёмся к более распространённым системам объектно-ориентированного программирования. Чего я никогда не мог понять, так это отношения объектов с внутренним состоянием. До изучения ООП всё было просто и прозрачно: есть структуры, хранящие несколько связанных данных, есть процедуры (функции), их обрабатывающие. выгулять(собаку), снятьс(аккаунт, сумма). Потом пришли объекты, и это было тоже ничего (хотя читать программы стало гораздо сложней — моя собака выгуливала [кого?], а аккаунт снимал деньги [откуда?]). Затем я узнал про сокрытие данных. Я всё ещё мог выгулять собаку, но вот посмотреть состав её пищи уже не мог. Пища не выполняла никаких действий (наверное, можно было написать, что пища.съесть(собака), но я всё-таки предпочитаю, чтобы моя собака ела пищу, а не наоборот). Пища — это просто данные, а мне (и моей собаке) нужно было просто получить к ним доступ. Всё просто. Но в рамки парадигмы влезть было уже невозможно, как в старые джинсы конца 90-х.

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

Не успел я насладиться просветлением, как увидил в интернетах слово stateless (готов поклясться, оно было окружено сиянием, а над буквами t и l висел нимб). Короткое изучение литературы открыло чудесный мир прозрачного потока управления и простой многопоточности без необходимости отслеживать согласованность объекта. Конечно, мне сразу захотелось прикоснуться к этому чудесному миру. Однако это означало полный отказ от любых правил — теперь было непонятно, следует ли собаке самой себя выгуливать, или для этого нужен специальный ВыгулМенеджер; нужен ли аккаунт, или со всей работой справится Банк, а если так, то должен он списывать деньги статически или динамически и т.д. Количество вариантов использования возрасло экспоненциально, и все варианты в будущем могли привести к необходимости серьёзного рефакторинга.

Я до сих пор не знаю, когда объект следует сделать stateless, когда stateful, а когда просто контейнером данных. Иногда это очевидно, но чаще всего нет.

Типизация: статическая или динамическая?

Еща одна вещь, с которой я не могу определиться относительно таких языков, как C# и Java, это являются они статически или динамически типизированными. Наверное большинство людей воскликнет «Что за глупость! Конечно статически типизированными! Типы проверяются во время компиляции!». Но действительно ли всё так просто? Правда ли, что программист, прописывая в параметрах метода тип X может быть уверен, что в него всегда будут передаваться объекты именно типа X? Верно — не может, т.к. в метод X можно будет передать параметр типа X или его наследника. Казалось бы, ну и что? Наследники класса X всё равно будут иметь те же методы, что и X. Методы методами, а вот логика работы может оказаться совершенно другой. Самый распространённый случай, это когда дочерний класс оказывается соптимизированным под другие нужды, чем X, а наш метод может рассчитывать именно на ту оптимизацию (если вам такой сценарий кажется нереалистичным, попробуйте написать плагин к какой-нибудь развитой open source библиотеке — либо вы потратите несколько недель на разбор архитектуры и алгоритмов библиотеки, либо будете просто наугад вызывать методы с подходящей сигнатурой). В итоге программа работает, однако скорость работы падает на порядок. Хотя с точки зрения компилятора всё корректно. Показательно, что Scala, которую называют наследницей Java, во многих местах по умолчанию разрешает передавать только аргументы именно указанного типа, хотя это поведение и можно изменить.

Другая проблема — это значение null, которое может быть передано практически вместо любого объекта в Java и вместо любого Nullable объекта в C#. null принадлежит сразу всем типам, и в то же время не принадлежит ни одному. null не имеет ни полей, ни методов, поэтому любое обращение к нему (кроме проверки на null) приводит к ошибке. Вроде бы все к этому привыкли, но для сравнения Haskell (да и та же Scala) заставлют использовать специальные типы (Maybe в Haskell, Option в Scala) для обёртки функций, которые в других языках могли бы вернуть null. В итоге про Haskell часто говорят «скомпилировать программу на нём сложно, но если всё-таки получилось, значит скорее всего она работает корректно».

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

Какая разница, как называется такая типизация, если все правила всё равно известны? Разница в том, с какой стороны подходить к проектированию архитектуры. Существует давний спор, как строить систему: делать много типов и мало функций, или мало типов и много функций? Первый подход активно используется в Haskell, второй в Lisp. В современных объектно-ориентированных языках используется что-то среднее. Я не хочу сказать, что это плохо — наверное у него есть свои плюсы (в конце концов не стоит забывать, что за Java и C# стоят мультиязыковые платформы), но каждый раз приступая к новому проекту я задумываюсь, с чего начать проектирования — с типов или с функционала.

И ещё…

Я не знаю, как моделировать задачу. Считается, что ООП позволяет отображать в программе объекты реального мира. Однако в реальности у меня есть собака (с двумя ушами, четырмя лапами и ошейником) и счёт в банке (с менеджером, клерками и обеденным перерывом), а в программе — ВыгулМенеджер, СчётФабрика… ну, вы поняли. И дело не в том, что в программе есть вспомогательные классы, не отражающие объекты реального мира. Дело в том, что поток управления изменяется. ВыгулМенеджер лишает меня удовольствия от прогулки с собакой, а деньги я получаю от бездушного БанкСчёта (эй, где та милая девушка, у которой я менял деньги на прошлой неделе?).

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

Я также не знаю, как правильно декомпозировать функционал. В Python или C++, если мне нужна была маленькая функция для преобразования строки в число, я просто писал её в конце файла. В Java или C# я вынужден выносить её в отдельный класс StringUtils. В недо-ОО-языках я мог объявить ad hoc обёртку для возврата двух значений из функции (снятую сумму и остаток на счету). В ООП языках мне придётся создать полноценный класс РезультатТранзакции. И для нового человека на проекте (или даже меня самого через неделю) этот класс будет выглядеть точно таким же важным и фундаментальным в архитектуре системы. 150 файлов, и все одинаково важные и фундаментальные — о да, прозрачная архитектура, прекрасные уровни абстракции.

Я не умею писать эффективные программы. Эффективные программы используют мало памяти — иначе сборщик мусора будет постоянно тормозить выполнение. Но чтобы совершить простейшую операцию в объектно-ориентированных языках приходится создавать дюжину объектов. Чтобы сделать один HTTP запрос мне нужно создать объект типа URL, затем объект типа HttpConnection, затем объект типа Request… ну, вы поняли. В процедурном программировании я бы просто вызвал несколько процедур, передав им созданную на стеке структуру. Скорее всего, в памяти был бы создан всего один объект — для хранения результата. В ООП мне приходится засорять память постоянно.

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

Коротко об истории объектно-ориентированного программирования / Хабр

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

Если вам интересно узнать, какой язык в действительности был первым ООП-языком на свете, могут ли Java и C# называться чистыми ООП-языками, а также проникнуться некоторыми другими деталями, приглашаю вас под кат…

Сначала перевод об истории ООП из Википедии:

«Термины «объектно-» и «ориентированный» в современном смысле этих слов появились в MIT в конце 1950 начале 1960 годов. В среде специалистов по искусственному интеллекту термин «объект» мог относиться к идентифицированным элементам (атомы Lisp) со свойствами (атрибутами). Алан Кэй позже писал, что понимание внутреннего устройства Лиспа оказало серьезное влияние на его мышление в 1966 г. Другим ранним примером ООП в MIT был Sketchpad созданный Иваном Сазерлендом в 1960-61. В глоссарии подготовленного в 1963 г. технического отчета, основанного на его диссертации о Sketchpad, Сазерленд определяет понятия «объект» и «экземпляр» с концепцией классов на основе «мастера» или «определения», хотя все эти термины относились к графическому представлению объектов [вкратце, в Sketchpad было основное изображение, на основе которого строились копии. При изменении основного – копии тоже менялись. Прим. пер.].

В ранней MIT-версии ALGOL AED-0 структуры данных («плексы» на диалекте Алгола) напрямую были связаны с процедурами, которые впоследствии были названы сообщениями, методами или функциями-членами.

Объекты, как формализованный концепт появились в программировании в 1960-х в Simula 67, модернизированной версии Simula I, языка программирования, ориентированного на дискретно-событийное моделирование. Авторы Simula — Оле-Йохан Даль и Кристен Нюгорд из Норвежского компьютерного центра в Осло. Simula разрабатывалась под влиянием SIMSCRIPT и предложенной Чарльзом Хоаром концепцией записей-классов. Simula включала в себя понятие классов и экземпляров (или объектов), а также подклассов, виртуальных методов, сопрограмм и дискретно-событийное моделирование как часть собственной парадигмы программирования. В языке использовался автоматический сборщик мусора, который был изобретен ранее для функционального языка Lisp. Simula использовалась тогда преимущественно для физического моделирования. Идеи Simula оказали серьезное влияние на более поздние языки, такие как Smalltalk, варианты Lisp (CLOS), Object Pascal, и C++.

Язык Smalltalk, который был изобретен в компании Xerox PARC Аланом Кэем (Alan Kay) и некоторыми другими учеными, фактически навязывал использование «объектов» и «сообщений» как базиса для вычислений. Создателей Smalltalk вдохновляли некоторые идеи Simula, но Smalltalk разрабатывался как полностью динамичная система, в которой классы могут создаваться и изменяться динамически, а не только статически как в Simula. Smalltalk и ООП с его помощью были представлены широкой аудитории в журнале Byte magazine в августе 1981.

В 1970-х Smalltalk Кэя сподвиг сообщество Lisp внедрить в язык объектно-ориентированные техники, которые были представлены разработчикам с помощью Lisp машины.

Эксперименты с различными расширениями Lisp в конечном итоге привели к созданию Common Lisp Object System (CLOS, части первого стандартизованного объектно-ориентированного языка, ANSI Common Lisp), который органично включал в себя как функциональное, так и объектно-ориентированное программирование и позволял расширять себя с помощью протокола Meta-object protocol. В 1980 было несколько попыток дизайна архитектур процессоров, которые включали бы в себя аппаратную поддержку работы с объектами в памяти, но все они были безуспешны. В качестве примеров можно привести Intel iAPX 432 и Linn Smart Rekursiv.

Объектно-ориентированное программирование развилось в доминирующую методологию программирования в начале и середине 1990 годов, когда стали широко доступны поддерживающие ее языки программирования, такие как Visual FoxPro 3.0, C++, и Delphi. Доминирование этой системы поддерживалось ростом популярности графических интерфейсов пользователя, которые основывались на техниках ООП. Пример тесной связи между динамической библиотекой GUI и объектно-ориентированного языка программирования можно найти посмотрев на фреймворк Cocoa на Mac OS X, который был написан на Objective-C, объектно-ориентированом расширении к С, основанном на Smalltalk с поддержкой динамических сообщений. Инструментарии ООП повлияли на популярность событийно-ориентированного программирования (хотя, эта концепция не ограничивается одним ООП). Некоторые даже думали, что кажущаяся или реальная связь с графическими интерфейсами – это то, что вынесло ООП на передний план технологий.

В ETH Zürich, Никлаус Вирт и его коллеги тоже исследовали такие предметы, как абстрация данных и модульное программирование, хотя эти подходы широко использовались и в 60-х и ранее. Modula-2 вышедшая в 1978 включала оба эти подхода, а ее последователь Oberon имел собственный подход к объктно-ориентированности, классам и прочему, непохожий на подход Smalltalk и совсем не похожий на подход C++.

Возможности ООП добавлялись во многие языки того времени, включая Ada, BASIC, Fortran, Pascal и другие. Их добавление в языки, изначально не разрабатывавшиеся для поддержки ООП часто приводило к проблемам с совместимостью и поддержкой кода.

Позднее стали появляться языки, поддерживающие как объектно-ориентированный подход, так и процедурный вроде Python и Ruby. Пожалуй, самыми коммерчески успешными объектно-ориентированными языками можно назвать Visual Basic.NET, C# и Java. И .NET и Java демонстрируют превосходство ООП.»

Теперь перевод небольшой части статьи «Как начиналось объектно-ориентированное программирование» за авторством Оле-Йохана Даля и Кристена Нюгорда.

«SIMULA I (1962-65) и Simula 67 (1967) — два первых объектно-ориентированных языка программирования. Simula 67 включала в себя большую часть концепций объектно-ориентированного программирования: классы и объекты, подклассы (наследование), виртуальные функции, безопасные ссылки и механизмы, позволяющие внести в программу коллекцию программных структур, описанных общим заголовком класса (префиксные блоки).

Алан Кэй из Xerox PARC использовал Simula как платформу для его разработки Smalltalk (первых версий языка в 1970-х), расширяя объектно-ориентированное программирование с помощью интеграции пользовательского интерфейса и интерактивного исполнения. Бьерн Страусструпп начал разработку C++ (в 1980-х) by привнеся основные концепции Simula в С.»

Теперь небольшое обобщение и заключение.

Как видите, получается, что первым ООП языком была Simula. Но первым «чистым» ООП языком был именно Smalltalk. «Чистым» иногда называют ООП язык, все типы которого являются или могут быть прозрачно представленными классами. В этом смысле Java чистым ООП языком стала только в версии 5, когда появилась возможность Autoboxing. C#, если я правильно понимаю, был чистым ООП языком с самого начала. Предлагаю в комментариях поломать копья на темы вроде «А в C# есть неуправляемые указатели, которые не могут быть представлены объектами», «А вообще чистым ООП языком может считаться только Smalltalk, в котором объектами представлено все, вплоть до блоков самой программы, ну или, в крайнем случае, Ruby» и «Чистый – значит, медленный. Ишь чего удумали, int объектом представлять!»

Некоторое время назад один странный хабраюзер заявил в одном из комментариев, что ООП изобрел Алан Кэй, что в чистом ООП нет наследования, что Java и C# по мнению автора термина «ООП» Алана Кэя ООП языками не являются и что Гослинг с Липпертом имеют… гм… проблемы, поскольку совершенно неверно считают, что изобретенные ими языки являются нормальными объектно-ориентированными.

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

Объектно-ориентированное программирование – парадигма, научный подход к программированию, который разрабатывался не в вакууме, а большой группой ученых. Вклад Кэя в ООП неоценим, но говорить, что ООП – целиком и полностью его изобретение будет несправедливо по отношению ко многим другим ученым, работавшим как вместе с ним, так и отдельно. Кэй действительно когда-то говорил, “I didn’t like the way Simula I or Simula 67 did inheritance (though I thought Nygaard and Dahl were just tremendous thinkers and designers). So I decided to leave out inheritance as a built-in feature until I understood it better.” Как вы понимаете, монополия на изобретение ООП им не заявлялась.

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

Если вы не согласны, приглашаю продолжить дискуссию в комментах.

объектно ориентированное программирование: основные принципы ооп

Объектно-ориентированное программирование (как расшифровывается ООП) – это, прежде всего, парадигма программирования.
Парадигма программирования определяет то, как программист видит выполнение программы.
Так, для парадигмы ООП характерно, что программист рассматривает программу в виде набора взаимодействующих объектов, в то время как, например, в функциональном программировании программа представляется в виде последовательности вычисления функций. Процедурное программирование или, как его еще правильно называют, классическое операциональное, подразумевает написание алгоритма для решения задачи; при этом ожидаемые свойства конечного результата не описываются и не указываются. Структурное программирование в основном придерживается тех же принципов, что и процедурное, лишь немного дополняя их полезными приемами.
Парадигмы непроцедурного программирования, к которым можно отнести объектно-ориентированную парадигму, имеют совершенно другие идеи.
Определение Гради Буча гласит: “Объектно-ориентированное программирование – это методология программирования, которая основана на представлении программы в виде совокупности объектов, каждый из которых является реализацией определенного класса (типа особого вида), а классы образуют иерархию на принципах наследуемости”.
Структурное и объектно-ориентированное программирование строятся на таком научном методе как декомпозиция — метод, который использует структуру задачи и позволяет разбить решение общей большой задачи на решение последовательности меньших задач. Декомпозиция ООП происходит не по алгоритмам, а по объектам, использующимся при решении задачи. Данная декомпозиция уменьшает размер программных систем благодаря повторному использованию общих механизмов. Известно, что системы визуального программирования или системы, построенные на принципах объектно-ориентированного программирования, являются более гибкими и легче эволюционируют со временем.

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

Сегодня существует достаточное количество объектно-ориентированных языков программирования, наиболее популярными из которых в настоящее время являются C++, Delphi, Java, Visual Basic, Flash. Но, кроме того, многие языки, которые принято причислять к процедурной парадигме, тоже обладают свойствами ООП, имея возможность работать с объектами. Так, объектно-ориентированное программирование в C — это большой раздел программирования на данном языке, то же самое касается ООП в python и многих других структурных языках.

Говоря об ООП, часто всплывает еще одно определение — визуальное программирование. Оно дополнительно предоставляет широкие возможности использования прототипов объектов, которые определяются как классы объектов.
События. Во многих средах визуального программирования реализована характеристика (помимо инкапсуляции, полиморфизма и наследования) объекта – событие. Событиями в объектно-ориентированном программировании называется возможность обработки так называемых сообщений (или событий), получаемых от операционной системы Windows или самой программы. Данный принцип характерен для всех компонентов среды, которые обрабатывают различные события, возникающие в процессе выполнения программы. По сути, событие — это некоторое действие, которое активизирует стандартную реакцию объекта. Событием может рассматриваться, например, щелчок по кнопке мыши, наведение курсора мыши на пункт меню, открытие вкладки и т.п. Очередность выполнения тех или иных действий определяется как раз таки событиями, возникающими в системе, и реакцией на них объектов.
Классы и объекты в ООП — различные понятия. Понятие класса в ООП – это тип данных (такой же как, например, Real или String), а объект – конкретный экземпляр класса (его копия), хранящийся в памяти компьютера как переменная соответствующего типа.
Класс является структурным типом данных. Класс включает описание полей данных, а также процедур и функций, которые работают с этими полями данных. Метод ООП – это и есть такие процедуры и функции применительно к классам.
Классы имеют поля (как тип данных запись — record), свойства, которые похожи на поля, но имеют дополнительные описатели, определяющие механизмы записи и считывания данных и методы — подпрограммы, которые направленны на изменение полей и свойств класса.

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

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

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

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

Полиморфизм ООП

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

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

НОУ ИНТУИТ | Лекция | Объектно-ориентированный подход к программированию

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

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

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

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

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

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

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

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

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

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

Наиболее известным примером объектно-ориентированного языка программирования является язык C++, развившийся из императивного языка С. Его прямым потомком и логическим продолжением является язык С#, который изучается в данном курсе.
Другие примеры объектно-ориентированных языков программирования: Visual Basic, Java, Eiffel, Oberon.

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

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

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

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

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

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

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

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

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

Объектно-ориентированный подход — это… Что такое Объектно-ориентированный подход?

Главные понятия и разновидности

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

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

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

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

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

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

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

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

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

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

Тимоти Бадд пишет[1]:

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

Определение ООП

По мнению Алана Кея, создателя языка Smalltalk, которого считают одним из «отцов-основателей» ООП, объектно-ориентированный подход заключается в следующем наборе основных принципов (цитируется по вышеупомянутой книге Т. Бадда[1]).

  1. Всё является объектом.
  2. Вычисления осуществляются путём взаимодействия (обмена данными) между объектами, при котором один объект требует, чтобы другой объект выполнил некоторое действие. Объекты взаимодействуют, посылая и получая сообщения. Сообщение — это запрос на выполнение действия, дополненный набором аргументов, которые могут понадобиться при выполнении действия.
  3. Каждый объект имеет независимую память, которая состоит из других объектов.
  4. Каждый объект является представителем (экземпляром) класса, который выражает общие свойства объектов.
  5. В классе задаётся поведение (функциональность) объекта. Тем самым все объекты, которые являются экземплярами одного класса, могут выполнять одни и те же действия.
  6. Классы организованы в единую древовидную структуру с общим корнем, называемую иерархией наследования. Память и поведение, связанное с экземплярами определённого класса, автоматически доступны любому классу, расположенному ниже в иерархическом дереве.

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

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

Концепции

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

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

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

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

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

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

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

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

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

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

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

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

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

Подходы к проектированию программ в целом

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

Объектно-ориентированное проектирование основывается на описании структуры и поведения проектируемой системы, то есть, фактически, в ответе на два основных вопроса:

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

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

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

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

Родственные методологии

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

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

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

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

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

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

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

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

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

Критика ООП

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

Обычно сравнивают объектное и процедурное программирование:

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

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

  • Исследование Thomas E. Potok, Mladen Vouk и Andy Rindos [1] показало отсутствие значимой разницы в продуктивности разработки программного обеспечения между ООП и процедурным подходом.
  • Кристофер Дэйт указывает на невозможность сравнения ООП и других технологий во многом из за отсутствия строгого и общепризнанного определения ООП (C. J. Date, Introduction to Database Systems, 6th-ed., Page 650)
  • Александр Степанов, в одном из своих интервью, указывал на то, что ООП «методологически неправильно» и что «… ООП практически такая же мистификация как и искусственный интеллект…» ([2]).
  • Фредерик Брукс (Frederick P. Brooks, Jr.) в своей статье «No Silver Bullet. Essence and Accidents of Software Engineering» (Computer Magazine; April 1987) указывает на то, что наиболее сложной частью создания программного обеспечения является « … спецификация, дизайн и тестирование концептуальных конструкций, а отнюдь не работа по выражению этих концептуальных конструкций…». ООП (наряду с такими технологиями как искусственный интеллект, верификация программ, автоматическое программирование, графическое программирование, экспертные системы и др), по его мнению, не является «серебряной пулей», которая может снизить сложность разработки программных систем. По его мнению «…ООП позволяет сократить только привнесённую сложность в выражение дизайна. Дизайн остаётся сложным по своей природе…». ([3])
  • Эдсгер Дейкстра указывал: «… то о чём общество в большинстве случаев просит — это змеиное масло. Естественно, „змеиное масло“ имеет очень впечатляющие имена, иначе будет очень трудно что-то продать: „Структурный анализ и Дизайн“, „Программная инженерия“, „Модели зрелости“, „Управляющие информационные системы“ (Management Information Systems), „Интегрированные среды поддержки проектов“, „Объектная ориентированность“, „Реинжиниринг бизнес-процессов“…» — EWD 1175: The strengths of the academic enterprise
  • Никлаус Вирт считает, что ООП — не более чем тривиальная надстройка над структурным программированием, и преувеличение её значимости, выражающееся, в том числе, во включении в языки программирования всё новых модных «объектно-ориентированных» средств, вредит качеству разрабатываемого программного обеспечения.
  • Патрик Киллелиа в своей книге «Тюнинг веб-сервера» писал: «… ООП предоставляет вам множество способов замедлить работу ваших программ …»

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

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

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

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

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

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

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

  • Конструкторы, деструкторы, финализаторы.
  • Свойства (аксессоры).
  • Индексаторы.
  • Интерфейсы — как альтернатива множественному наследованию.
  • Переопределение операторов для классов.

Часть языков (иногда называемых «чисто объектными») целиком построена вокруг объектных средств — в них любые данные (возможно, за небольшим числом исключений в виде встроенных скалярных типов данных) являются объектами, любой код — методом какого-либо класса и невозможно написать программу, в которой не использовались бы объекты. Примеры подобных языков — Java или Ruby. Другие языки (иногда используется термин «гибридные») включают ООП-подсистему в исходно процедурный язык. В них существует возможность программировать, не обращаясь к объектным средствам. Классические примеры — C++ и Delphi Pascal.

Примечания

  1. 1 2 Бадд Т. Объектно-ориентированное программирование в действии / Перев. с англ. — СПб.: Питер, 1997. ISBN 5-88782-270-8
  2. Гради Буч. Объектно-ориентированный анализ и проектирование с примерами приложений на C++. 2-е изд. / Пер. с англ. — М.:»Издательство Бином», СПб:»Невский диалект», 1998 г. ISBN 5-7989-0067-3, ISBN 5-7940-0017-1, стр. 276—278

См. также

Литература

  • Иан Грэхем Объектно-ориентированные методы. Принципы и практика = Object-Oriented Methods: Principles & Practice. — 3-е изд. — М.: «Вильямс», 2004. — С. 880. — ISBN 0-201-61913-X
  • Антони Синтес Освой самостоятельно объектно-ориентированное программирование за 21 день = Sams Teach Yourself Object-Oriented Programming in 21 Days. — М.: «Вильямс», 2002. — С. 672. — ISBN 0-672-32109-2

Ссылки

НОУ ИНТУИТ | Лекция | Объектно-ориентированный подход к программированию

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

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

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

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

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

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

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

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

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

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

Наиболее известным примером объектно-ориентированного языка программирования является язык C++, развившийся из императивного языка С. Его прямым потомком и логическим продолжением является язык С#, который изучается в данном курсе.
Другие примеры объектно-ориентированных языков программирования: Visual Basic, Java, Eiffel, Oberon.

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

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

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

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

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

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

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

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

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

Концепции объектно-ориентированного программирования (Руководства по Java ™> Изучение языка Java)

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

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

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

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

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

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

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

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

.

концепций объектно-ориентированного программирования | 101 Вычисления

Классы и объекты

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

Класс состоит из набора состояний (он же атрибутов или свойств ) и поведений (a.k.a. методов ).

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

Конструктор

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

Superhero Class

Superhero Class

Давайте рассмотрим класс класса Superhero .
Атрибуты супергероя:

  • имя (строка)
  • superpower (строка)
  • сила (целое число)

Вот некоторые из методов супергероя:

  • init () — это конструктор , который может принимать некоторые параметры, используемые для инициализации значения по умолчанию супергероя, который будет создан.
  • ходьба ()
  • пробег ()
  • прыжок ()

На диаграмме справа представлен класс Superhero с его атрибутами и методами. Обратите внимание, что нам не нужно представлять конструктор на этой диаграмме, поскольку предполагается, что все классы имеют конструктор. (В Python конструктором класса является функция __init __ () .)

Создание экземпляров объектов из класса супергероев

В нашей видеоигре будет 3 супергероя: Человек-паук, Супермен и Бэтмен.Таким образом, мы создадим 3 объекта из нашего класса Superhero .

человек-паук = новый супергерой («Человек-паук», «Наручные стрелки, стреляющие паутиной», 10)
Бэтмен = новый супергерой («Бэтмен», «Ночное видение», 10)
superman = new Superhero («Супермен», «Может летать», 20)

человек-паук = новый супергерой («Человек-паук», «Наручные стрелки для стрельбы из паутины», 10)

Бэтмен = новый супергерой («Бэтмен», «Ночное видение», 10)

супермен = новый супергерой ( «Супермен», «Может летать», 20)

Соглашение об именах

При кодировании идентификатор класса начинается с заглавной буквы e.г. Супергерой .
Идентификатор объекта начинается со строчной буквы, например человек-паук .

Наследование

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

Например, давайте рассмотрим интернет-магазин, который продает различные типы товаров (предметов), такие как DVD, книги и Mp3.

Класс предмета

Код такого интернет-магазина может быть основан на использовании класса под названием Предмет . Этот класс будет содержать все атрибуты и методы, которые потребуются каждому элементу:

  • Атрибуты: наименование, описание, цена
  • Методы: viewFullDescription (), addToShoppingBasket (), removeFromShoppingBasket ()

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

    Класс MP3:

    • Атрибуты: художник, продолжительность
    • Методы: play (), download ()

    DVD Класс:

    • Атрибуты: сертификат, срок действия, актеры
    • Методы: viewTrailer ()

    Книжный класс:

    • Атрибуты: автор, жанр, количество страниц
    • Методы: previewContent ()

Подклассы MP3, DVD и Book будут наследовать свойства и методы родительского класса (Item), как показано ниже зеленым цветом.

    Класс MP3:

    • Атрибуты: название, описание, цена, исполнитель, продолжительность
    • Методы: viewFullDescription (), addToShoppingBasket (), removeFromShoppingBasket (), play (), download ()

    DVD Класс:

    • Атрибуты: имя, описание, цена, сертификат, срок действия, участники
    • Методы: viewFullDescription (), addToShoppingBasket (), removeFromShoppingBasket (), viewTrailer ()

    Книжный класс:

    • Атрибуты: имя, описание, цена, автор, жанр, номер Страницы
    • Методы: viewFullDescription (), addToShoppingBasket (), removeFromShoppingBasket (), previewContent ()
Схема классов

Унаследованные свойства и методы подкласса не , а не нужно дублировать на диаграмме классов, поскольку понятно, что они унаследованы от родительского класса:

Терминология

Родительский класс также называется мастер-класс или базовый класс .
Дочерний класс также называется подклассом или производным классом .

Множественное наследование

Класс может наследовать от двух или более родительских классов . В этом случае он унаследует свойства и методы всех родительских классов.

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

Инкапсуляция

Частный vs.Общественный

При определении атрибутов и методов класса они могут быть определены как private или public .

Доступ к частному атрибуту или частному методу возможен только из методов класса. К ним нельзя получить прямой доступ извне класса.

Доступ к общему атрибуту или общедоступному методу можно получить из любого места (из других методов класса или извне класса).

Например, давайте рассмотрим класс Car со следующими атрибутами и методами:

В нашей гоночной игре мы бы создали экземпляр объекта playerCar из этого класса Car .

playerCar = новый автомобиль («Мини», «Купер»)

playerCar = new Car («Мини», «Купер»)

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

playerCar.speed = 70
playerCar.fuelLevel = 45
playerCar.accelerate (5) # увеличить скорость на 5 миль в час
playerCar.drive (10) # проехать 10 миль
ПЕЧАТЬ («Ваш текущий уровень топлива:»
ПЕЧАТЬ playerCar.fuelLevel

playerCar.speed = 70

playerCar.fuelLevel = 45

playerCar.accelerate (5) # увеличить скорость на 5 миль в час

playerCar.drive (10) # проехать 10 миль

PRINT («Ваш текущий уровень топлива: «

ПЕЧАТЬ playerCar.fuelLevel

Однако считается хорошей практикой «скрывать» некоторые свойства или методы от «внешнего мира», делая их частными.В этом случае к этим частным свойствам и методам нельзя получить доступ извне класса.

Например, в приведенном выше примере мы можем решить, что оба атрибута speed и fuelLevel должны быть установлены как частные. В этом случае ни одна из следующих трех строк не будет компилироваться и, следовательно, их придется удалить:

playerCar.speed = 70
playerCar.fuelLevel = 45
ПЕЧАТЬ playerCar.fuelLevel

playerCar.speed = 70

playerCar.fuelLevel = 45

ПЕЧАТЬ playerCar.fuelLevel

Мы по-прежнему можем изменять содержимое fuelLevel и скорость автомобиля в коде методов fillUp (), accelerate (), slowDown () и drive () автомобиля.

playerCar.fillUp (45) # Добавить 45 литров бензина в бак
playerCar.accelerate (50) # увеличить скорость на 50 миль в час
playerCar.drive (10) # проехать 10 миль

playerCar.fillUp (45) # Добавьте 45 литров бензина в бак

playerCar.accelerate (50) # увеличьте скорость на 50 миль в час

playerCar.drive (10) # проехать 10 миль

Геттеры и сеттеры

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

Например, чтобы получить fuelLevel машины игрока, мы могли бы иметь новый общедоступный метод под названием getFuelLevel () и использовать его для информирования пользователя о том, сколько бензина осталось в его баке.

ПЕЧАТЬ «Ваш текущий уровень топлива:»
ПЕЧАТЬ player.getFuelLevel ()

ПЕЧАТЬ «Ваш текущий уровень топлива:»

ПЕЧАТЬ player.getFuelLevel ()

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

player.setFuelLevel (0) # Опорожнение топливного бака

player.setFuelLevel (0) # Опорожнение топливного бака

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

Например, если fuelLevel является общедоступным свойством, следующий код будет принят, даже если в автомобиле не может быть 999 литров бензина (999> tankCapacity)!

playerCar.fuelLevel = 999

playerCar.fuelLevel = 999

Сделав свойство fuelLevel закрытым и принудительно используя открытый метод setFuelLevel () (установщик), мы можем реализовать в коде метода setFuelLevel () проверку validatiom , которую нельзя обойти , чтобы гарантировать, что данный параметр является положительным числом, меньшим или равным tankCapacity.например

ФУНКЦИЯ setFuelLevel (количество)
ЕСЛИ количество <0 ТО fuelLevel = 0 ИНАЧЕ ЕСЛИ количество> емкость бака ТО
fuelLevel = емкость бака
ELSE
fuelLevel = количество
КОНЕЦ ЕСЛИ
КОНЕЧНАЯ ФУНКЦИЯ

FUNCTION setFuelLevel (количество)

IF количество <0 THEN

fuelLevel = 0

ELSE IF количество> tankCapacity THEN

fuelLevel = tankCapacity

ELSE

fuelCevel = количество

END IF

END 900

Установщик может быть использован в нашем коде следующим образом:

playerCar.setFuelLevel (45) # сбросить уровень топлива до 45 литров

playerCar.setFuelLevel (45) # сбросить уровень топлива до 45 литров

Полиморфизм

Полиморфизм означает «множественные формы». В ООП эти несколько форм относятся к нескольким формам одного и того же метода, где одно и то же имя метода может использоваться в разных классах или одно и то же имя метода может использоваться в одном классе с немного разными параметрами.Есть две формы полиморфизма: перегрузка и перегрузка.

Полиморфизм замещения

Рассмотрим следующую диаграмму классов, в которой классы ElectricCar и PetrolCar наследуются от класса Car .

В этом классе классы PetrolCar и ElectricCar наследуют метод drive () от родительского класса Car. Однако этот метод должен быть реализован иначе. , поскольку вы не ныряете на электромобиле так же, как водите бензиновый.Код, используемый в обоих методах, будет отличаться и перезаписывать код родительского класса. Это то, что означает замещающий полиморфизм : когда метод из подкласса должен быть перезаписан, чтобы переопределить метод, унаследованный от родительского класса.

Иногда, как в нашем примере, метод drive () класса Car только определен, но не реализован вообще (пустая функция без кода) в классе Car . Вместо этого он будет перезаписан и правильно реализован в подклассах.

Полиморфизм перегрузки

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

Например, давайте рассмотрим наш класс Superhero, в который мы хотели бы добавить метод для установки даты рождения (DoB) супергероя. Мы могли бы написать этот же метод несколько раз, чтобы принимать разные параметры, например:

Метод может принимать параметр даты в виде строки в формате «ДД / ММ / ГГГГ».

ПРОЦЕДУРА setDoB (строка: дата) # дата в формате ДД / ММ / ГГГГ

PROCEDURE setDoB (string: date) # дата в формате ДД / ММ / ГГГГ

е.г.

spiderman.setDob («15.08.1962»)

spiderman.setDob («15.08.1962»)

Тот же метод можно реализовать второй раз, взяв три следующих параметра:

ПРОЦЕДУРА setDoB (целое число: день, целое число: месяц, целое число: год)

ПРОЦЕДУРА setDoB (целое число: день, целое число: месяц, целое число: год)

е.г.

spiderman.setDob (15,08,1962)

spiderman.setDob (15,08,1962)

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

Абстрактные классы

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

Например, давайте вернемся к системе онлайн-покупок, где мы продаем три типа товаров: MP3, DVD и книги. Класс MP3 , класс DVD и класс Book наследуются от родительского класса Item . Объекты будут созданы из класса MP3 , класса DVD или класса Book .Мы никогда не будем создавать экземпляр объекта непосредственно из класса Item . Вот почему класс Item называется абстрактным классом .

Итак, абстрактный класс:

  • Невозможно создать экземпляр напрямую.
  • Может использоваться только через наследование.

.

Концепции объектно-ориентированного программирования — CodeProject

Введение

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

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

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

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

Объект

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

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

Класс

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

Экземпляр

Экземпляр — это фактический объект, созданный во время выполнения. Можно иметь экземпляр класса или конкретного объекта.

Государство

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

Метод

Метод описывает возможности объекта. Собака умеет лаять. Итак, bark () — один из методов класса Dog.

Сообщение передается

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

Абстракция

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

Инкапсуляция

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

Хранение данных и функций в одном блоке (классе) — это инкапсуляция. Данные не могут быть доступны для внешнего мира, и только те функции, которые хранятся в классе, могут получить к ним доступ.

Наследование

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

Полиморфизм

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

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

Обобщение

Обобщение описывает отношения «есть-а», которые представляют иерархию между классами объектов. Например: — «фрукт» — это обобщение слов «яблоко», «апельсин», «манго» и многих других. животное является обобщением животное .

Специализация

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

Преимущества ООП

Объектно-ориентированное программирование имеет следующие преимущества перед традиционными подходами:

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

Ссылки

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

История

  • 14 Июль 2008 г .: Начальная должность

.

Как объяснить концепции объектно-ориентированного программирования шестилетнему ребенку

Александра Петкова

Вы замечали, что одни и те же клише вопросы всегда задаются на собеседовании — снова и снова?

Я уверен, вы понимаете, о чем я.

Например:

Где вы видите себя через пять лет?

или, что еще хуже:

Что вы считаете своей самой большой слабостью?

Ух… дай мне передохнуть. Считаю ответ на этот вопрос большой слабостью! Во всяком случае, я не о том.

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

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

Сегодня я хочу поговорить о подобном типе вопросов в мире программирования:

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

Я был по обе стороны этого вопроса. Это одна из тех тем, которые задают так часто, что вы не можете позволить себе не знать.

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

  1. Готовился ли кандидат к этому интервью?
    Бонусные баллы, если ответ услышишь сразу — это серьезный подход.
  2. Кандидат прошел этап обучения?
    Понимание принципов объектно-ориентированного программирования (ООП) показывает, что вы вышли за рамки копирования и вставки из руководств — вы уже видите вещи с более высокой точки зрения.
  3. Понимание кандидата глубокое или поверхностное?
    Уровень компетенции по этому вопросу часто равен уровню компетенции по большинству других предметов . Доверьтесь мне.

Как выглядит разработчик начального уровня после ответа на этот вопрос!

Четыре принципа объектно-ориентированного программирования: инкапсуляция , абстракция , наследование , и полиморфизм .

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

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

Инкапсуляция

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

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

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

Допустим, мы создаем крошечную игру Sims.Есть люди и есть кошка. Они общаются друг с другом. Мы хотим применить инкапсуляцию, поэтому мы инкапсулируем все «cat»

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *