К свойствам объектно ориентированных языков программирования относятся. Принципы объектно-ориентированного программирования. Зачем же это нужно

Общая информация

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

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

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

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

Полиморфизм

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

Языки ООП

Принципы ООП используются в таких наиболее популярных языках программирования, как C++ и Java, на которых разработана значительная часть программ и приложений. Есть и менее используемые языки ООП - это Delphi, Object Pascal, Ruby и многие другие.

Критика ООП

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

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

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

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

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

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

История

Основатели ООП - выдающиеся норвежские ученые Кристен Нигаард (Cristen Nygaard) и Оле-Йохан Даль (Ole-Johan Dahl). Работая над моделированием судовождения, Нигаард понял, что существующие программные средства малоэффективны в создании столь сложных программ, и тогда Нигаард начал разрабатывать концепции нового программирования, позволяющего преодолеть барьеры сложности, и которое впоследствии было названо объектно-ориентированным (сам термин был придуман Аланом Кеем, автором языка Java). Вместе с Оле-Йоханом Далем Нигаард разработал основные положения ООП и практические механизмы их реализации, которые затем были воплощены в первом ООЯ Симула (Simula). Заслуги этих ученых были по достоинству оценены мировым научным сообществом, и в 2001 году Нигаард и Даль стали лауреатами премии имени Алана Тьюринга - своеобразного аналога Нобелевской премии в области computer science.

Язык Симула пользовался известностью в академических кругах, однако по ряду причин не завоевал популярности среди разработчиков коммерческого ПО. Тем не менее основные идеи и возможности ООП были очень привлекательны для программистов. Впоследствии были созданы другие ООЯ: SmallTalk (1980), C++ (1985), Eiffel (1986), Object Pascal (1986) и Delphi (1995), Oberon-2 (1991), Java (1991), Visual Basic (1991) и многие другие. Некоторые из этих языков стали промышленными стандартами в программировании.

Особенности ООП

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

В обыденной жизни люди используют (пусть даже неосознанно) различные приемы “экономии мышления”, позволяющие осмысливать и выражать сложные явления в простых понятиях. Типичными приемами “экономии мышления” являются:

· абстрагирование (отбрасывание несущественных деталей);

· обобщение (выделение общих существенных признаков у разных явлений или предметов);

· классификация (осознание связи между явлениями и степени их схожести).

Эти простые приемы помогают человеку справиться со сложностью рассматриваемых явлений. И объектно-ориентированные языки программирования также должны предоставлять подобные средства для “борьбы со сложностью” программ. Для реализации объектно-ориентированного подхода в языки программирования вводятся новые понятия:

· объекты - особые программные структуры, объединяющие данные и алгоритмы их обработки;

· инкапсуляция - сокрытие подробностей функционирования объектов;

· наследование - “сокращенный” способ создания новых классов;

· полиморфизм - возможность применения нескольких реализаций одной функции.

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

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

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

В некоторых языках (C++, Java) объекты называются экземплярами класса (instances).

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

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

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

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

Различные ООЯ предлагают разные возможности по инкапсуляции полей и методов (от полного отсутствия и до автоматического сокрытия всех полей). В промышленных ООЯ, таких, как C++, Java, Delphi, Eiffel и т.д., предусмотрены три уровня инкапсуляции полей и методов:

· public - на обращение к публичным полям и методам объектов нет никаких ограничений;

· protected - прямое обращение к защищенным полям и методам возможно только из методов данного класса и методов дочерних классов;

· private - прямое обращение к приватным полям и методам возможно исключительно из методов данного класса.

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

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

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

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

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

Совокупность всех классов-предков и классов-потомков называется иерархией классов .

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

Полиморфизм

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

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

В ООП есть два вида полиморфных методов - перегруженные и виртуальные .

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

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

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

Достоинства виртуальных методов проявляются только при использовании иерархии классов. Типичная схема использования виртуальных методов такова:

· В классе-предке иерархии объявляется полиморфный метод, который описывает некое полезное действие. При этом либо он использует виртуальный метод, либо сам является виртуальным.

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

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

Яркий пример подобного использования виртуальных методов - система графического оконного интерфейса Delphi или Visual Basic: каждый видимый элемент графического интерфейса - кнопка, ползунок, окно и т.п. - должен быть потомком класса TControl. В классе TControl вводятся общие полиморфные методы отрисовки элементов графического интерфейса, а любой его потомок может нарисовать себя на экране своим собственным способом.

Объектно-ориентированное программирование явно не упоминается в Стандарте 2004 года, хотя в Обязательном минимуме содержания образования по информатике для учащихся профильных заведений (Уровень Б) такая тема присутствовала: Объектно-ориентированное программирование: объект, свойства объекта, операции над объектом . Там же упоминалась и объектно-ориентированная технология программирования.

Тем не менее ООП не просто вошло в практику преподавания информатики (программирования) многих школ, но и присутствует на страницах школьных учебников (Угринович Н.Д. Информатика и информационные технологии. Учебник для 10–11-х классов, 2005. М.: БИНОМ. Лаборатория Знаний). Кроме того, в пропедевтическом курсе информатики для начальной школы (рабочие тетради авторского коллектива под руководством А.Горячева. 1–4-е классы) также вводятся понятия объекта и его свойств .

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

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

Фактически же ООП в школе рассматривается лишь как неотъемлемая часть визуального и компонентного программирования в современных профессиональных системах программирования, а в качестве объектов используются готовые объектные библиотеки различного уровня - это и библиотеки для построения графического интерфейса Windows-приложений, и многоцелевые универсальные библиотеки типов данных (например, STL в С++). Для примитивного использования этих библиотек достаточно знать и уметь применять несколько простейших правил синтаксиса языка программирования. Однако такие “знания” никоим образом не приближают учащихся ни к профессиональному овладению языком программирования, ни даже к пониманию ООП. Но, видимо, ничего страшного в этом нет. Школьная информатика и в профильной школе не ставит своей целью подготовку профессиональных программистов. Преподавание ООП - это специальная тема, даже на соответствующих специальностях вузов ее часто не изучают в достаточном объеме.

Не отрицая полностью предложение некоторых преподавателей информатики поставить объектно-ориентированный подход во главу угла изучения программирования, в том числе в школе, отметим, что ООП невозможно без таких базовых понятий, как программа, исполнитель, переменная, условие, цикл и т.д. Концепция ООП также включает в себя классическое процедурное программирование (см. “Подпрограммы ”), как механика Эйнштейна - механику Ньютона: достаточно представить себе процедурную программу как единственный объект с опущенным для простоты именем. Поэтому в первую очередь задача курса программирования в школе - научить базовым вещам. И лишь при возможности работы с современными визуальными средами программирования (Delphi, Visual Basic, Visual C++
и т.п.) познакомить с понятием объектов и их использованием в основном с помощью методики обучения программированию “по образцу”.

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

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

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

Терминология объектно-ориентированного программирования

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

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

Преимущества объектно-ориентированного программирования

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

  • Инкапсуляция обозначает сокрытие деталей реализации классов средствами награждения отдельных его членов соответствующими модификаторами доступа. Таким образом, вся функциональность объекта, нацеленная на взаимодействие с другими объектами программы группируется в открытый интерфейс, а детали тщательно скрываются внутри, что избавляет основной код бизнес-логики информационной системы от ненужных ему вещей. Инкапсуляция повышает надежность работы программного кода, поскольку гарантирует, что определенные данные не могут быть изменены за пределами содержащего их класса.
  • Наследование . Краеугольный камень ООП. В объектно-ориентированном программировании есть возможность наследовать структуру и поведение класса от другого класса. Класс, от которого наследуют, называется базовым или суперклассом, а класс, который получается вследствие наследования – производным или просто потомком. Любой класс может выступать как в роли суперкласса, так и в роли потомка. Связи наследования классов образуют иерархию классов. Множественным наследованием называют определение производного класса сразу от нескольких суперклассов. Не все объектно-ориентированные языки программирования поддерживают множественное наследование. Наследование – это эффективный способ выделения многократно используемых фрагментов кода, но у него есть и минусы, о которых будет рассказано далее.
  • Абстрагирование . Возможность объединять классы в отдельные группы, выделяя общие, значимые для них всех характеристики (общие поля и общее поведение). Собственно, абстрагирование и есть следствие наследования: базовые классы не всегда имеют свою проекцию на объекты реального мира, а создаются исключительно с целью выделить общие черты целой группы объектов. К примеру, объект мебель – это базовое понятие для стола, стула и дивана, всех их объединяет то, что это движимое имущество, часть интерьера помещений, и они могут быть выполнены для дома или офиса, а также относиться к “эконом” или “премиум” классу. В ООП есть для этого отдельное понятие абстрактный класс – класс, объекты которого создавать запрещено, но можно использовать в качестве базового класса. Наследование и абстрагирование позволяют описывать структуры данных программы и связи между ними точно так же, как выглядят соответствующие им объекты в рассматриваемой модели предметной области.

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

Диаграмма классов или иерархия наследования "Транспортные средства". Белые квадраты обозначают абстрактные классы.

  • Полиморфизм . Еще одно свойство, которое является следствием наследования. Дело в том, что объектно-ориентированные языки программирования позволяют работать с набором объектов из одной иерархии точно так же, как если бы все они были объектами их базового класса. Если вернуться к примеру про мебель, то можно предположить, что в контексте создания информационной системы для мебельного магазина в базовый класс для всех видов мебели разумно добавить общий для всех метод “показать характеристики”. При распечатке характеристик всех видов товара программа бы без разбору для всех объектов вызывала бы этот метод, а каждый конкретный объект уже сам бы решал, какую информацию ему предоставлять. Как это реализуется: Во-первых, в базовом классе определяют общий для всех метод с общим для всех поведением. В случае с нашим примером это будет метод, печатающий общие для любых типов мебели параметры. Во-вторых, в каждом производном классе, где это необходимо, переопределяют базовый метод (добавляют метод с тем же именем), где расширяют базовое поведение своим, например, выводят характеристики, свойственные только конкретному виду мебельной продукции. Метод в базовом классе иногда вообще не обязан содержать какой-либо код, а необходим только для того, чтобы определить имя и набор параметров – сигнатуру метода. Такие методы называют абстрактными методами, а классы, их содержащие, автоматически становятся абстрактными классами. Итак, полиморфизм – это возможность единообразного общения с объектами разных классов через определенный интерфейс. Идеология полиморфизма гласит, что для общения с объектом вам не нужно знать его тип, а нужно знать, какой интерфейс он поддерживает.
  • Интерфейс . В некоторых языках программирования (C#, Java) понятие интерфейса выделено явно - это не только открытые методы и свойства самого класса. Такие языки, как правило, не поддерживают множественного наследования и компенсируют это тем, что любой объект может иметь один базовый объект и реализовывать любое количество интерфейсов. Интерфейс в их интерпретации – это подобие абстрактного класса, содержащего только описание (сигнатуру) открытых методов и свойств. Реализация интерфейса ложится на плечи каждого класса, который собирается его поддерживать. Один и тот же интерфейс могут реализовывать классы абсолютно разных иерархий, что расширяет возможности полиморфизма. К примеру, интерфейс “сохранение/восстановление информации в базе данных” могли бы реализовывать как классы иерархии “мебель”, так и классы, связанные с оформлением заказов на изготовление мебели, а при нажатии на кнопку “сохранить” программа бы прошлась по всем объектами, запросила бы у них этот интерфейс и вызвала бы соответствующий метод.

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

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

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

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

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

Про то, что популярность объектно-ориентированного подхода к созданию программных продуктов огромна я уже сказал. Про то, что тех, кто стремится расширить эту парадигму довольно много, я тоже уже отметил. Но есть еще один способ выделиться среди огромного сообщества специалистов в информационных технологиях – это заявить, что ООП себя не оправдало, что это не панацея, а, скорее, плацебо. Есть среди этих людей действительно специалисты очень высокого класса, такие как Кристофер Дэйт, Александр Степанов, Эдсгер Дейкстра и другие, и их мнение заслуживает внимания, но есть и те, про которых говорят, что “плохому танцору всегда что-то мешает”. Вот они, наиболее очевидные недостатки ООП, на которые указывают специалисты:

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

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

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

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

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

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

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


Об объектах и классах

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

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

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

/** * Класс Треугольник. */ class Triangle { /** * Специальный метод, называемый конструктор класса. * Принимает на вход три параметра: * длина стороны А, длина стороны Б, * угол между этими сторонами(в градусах) */ Triangle(double sideA, double sideB, double angleAB) { this.sideA = sideA; this.sideB = sideB; this.angleAB = angleAB; } double sideA; //Поле класса, хранит значение стороны А в описываемом треугольнике double sideB; //Поле класса, хранит значение стороны Б в описываемом треугольнике double angleAB; //Поле класса, хранит угла(в градусах) между двумя сторонами в описываемом треугольнике /** * Метод класса, который рассчитывает площадь треугольника */ double getSquare() { double square = this.sideA * this.sideB * Math.sin(this.angleAB * Math.PI / 180); return square; } /** * Метод класса, который рассчитывает периметр треугольника */ double getPerimeter() { double sideC = Math.sqrt(Math.pow(this.sideA, 2) + Math.pow(this.sideB, 2) - 2 * this.sideA * this.sideB * Math.cos(this.angleAB * Math.PI / 180)); double perimeter = this.sideA + this.sideB + sideC; return perimeter; } }

Если мы внутрь класса добавим следующий код:

/** * Именно в этом месте запускается программа */ public static void main(String args) { //Значения 5, 17, 35 попадают в конструктор класса Triangle Triangle triangle1 = new Triangle(5, 17, 35); System.out.println("Площадь треугольника1: "+triangle1.getSquare()); System.out.println("Периметр треугольника1: "+triangle1.getPerimeter()); //Значения 6, 8, 60 попадают в конструктор класса Triangle Triangle triangle2 = new Triangle(6, 8, 60); System.out.println("Площадь треугольника1: "+triangle2.getSquare()); System.out.println("Периметр треугольника1: "+triangle2.getPerimeter()); }

то программу уже можно будет запускать на выполнение. Это особенность языка java. Если в классе есть такой метод

Public static void main(String args)

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

Triangle triangle1 = new Triangle(5, 17, 35);

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

System.out.println("Площадь треугольника1: "+triangle1.getSquare()); System.out.println("Периметр треугольника1: "+triangle1.getPerimeter());

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

Аналогично все происходит и для второго экземпляра класса Triangle .

Понимание сути классов и конструирования конкретных объектов - это уверенный первый шаг к пониманию методологии ООП.

Еще раз, самое важное:

ООП - это способ организации кода программы;

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

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


Три волшебных слова

ООП включает три ключевых подхода: наследование, инкапсуляцию и полиморфизм. Для начала, приведу определения из wikipedia :

Инкапсуляция - свойство системы, позволяющее объединить данные и методы, работающие с ними, в классе. Некоторые языки (например, С++) отождествляют инкапсуляцию с сокрытием, но большинство (Smalltalk, Eiffel, OCaml) различают эти понятия.

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

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

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


Итак, точка - это самая малая геометрическая фигура, которая является основой всех прочих построений (фигур). Поэтому именно точка выбрана в качестве базового родительского класса. Напишем класс точки на java:

/** * Класс точки. Базовый класс */ class Point { /** * Пустой конструктор */ Point() {} /** * Метод класса, который рассчитывает площадь фигуры */ double getSquare() { return 0; } /** * Метод класса, который рассчитывает периметр фигуры */ double getPerimeter() { return 0; } /** * Метод класса, возвращающий описание фигуры */ String getDescription() { return "Точка"; } }

У получившегося класса Point пустой конструктор, поскольку в данном примере мы работаем без конкретных координат, а оперируем только параметрами значениями сторон. Так как у точки нет никаких сторон, то и передавать ей никаких параметров не надо. Также заметим, что класс имеет методы Point::getSquare() и Point::getPerimeter() для расчета площади и периметра, оба возвращают 0. Для точки оно и логично.


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

/** * Класс Отрезок */ class LineSegment extends Point { LineSegment(double segmentLength) { this.segmentLength = segmentLength; } double segmentLength; // Длина отрезка /** * Переопределенный метод класса, который рассчитывает площадь отрезка */ double getSquare() { return 0; } /** * Переопределенный метод класса, который рассчитывает периметр отрезка */ double getPerimeter() { return this.segmentLength; } String getDescription() { return "Отрезок длиной: " + this.segmentLength; } }

Class LineSegment extends Point

означает, что класс LineSegment наследуется от класса Point . Методы LineSegment::getSquare() и LineSegment::getPerimeter() переопределяют соответствующие методы базового класса. Площадь отрезка всегда равняется нулю, а площадь периметра равняется длине этого отрезка.

Теперь, подобно классу отрезка, опишем класс треугольника(который также наследуется от класса точки):

/** * Класс Треугольник. */ class Triangle extends Point { /** * Конструктор класса. Принимает на вход три параметра: * длина стороны А, длина стороны Б, * угол между этими сторонами(в градусах) */ Triangle(double sideA, double sideB, double angleAB) { this.sideA = sideA; this.sideB = sideB; this.angleAB = angleAB; } double sideA; //Поле класса, хранит значение стороны А в описываемом треугольнике double sideB; //Поле класса, хранит значение стороны Б в описываемом треугольнике double angleAB; //Поле класса, хранит угла(в градусах) между двумя сторонами в описываемом треугольнике /** * Метод класса, который рассчитывает площадь треугольника */ double getSquare() { double square = (this.sideA * this.sideB * Math.sin(this.angleAB * Math.PI / 180))/2; return square; } /** * Метод класса, который рассчитывает периметр треугольника */ double getPerimeter() { double sideC = Math.sqrt(Math.pow(this.sideA, 2) + Math.pow(this.sideB, 2) - 2 * this.sideA * this.sideB * Math.cos(this.angleAB * Math.PI / 180)); double perimeter = this.sideA + this.sideB + sideC; return perimeter; } String getDescription() { return "Треугольник со сторонами: " + this.sideA + ", " + this.sideB + " и углом между ними: " + this.angleAB; } }

Тут нет ничего нового. Также, методы Triangle::getSquare() и Triangle::getPerimeter() переопределяют соответствующие методы базового класса.
Ну а теперь, собственно, тот самый код, который показывает волшебство полиморифзма и раскрывает мощь ООП:

Class Main { /** * Именно в этом месте запускается программа */ public static void main(String args) { //ArrayList - Это специальная структура данных в java, // позволяющая хранить объекты определенного типа в массиве. ArrayList figures = new ArrayList(); //добавляем три разных объекта в массив figures figures.add(new Point()); figures.add(new LineSegment(133)); figures.add(new Triangle(10, 17, 55)); for (int i = 0; i

Мы создали массив объектов класса Point , а поскольку классы LineSegment и Triangle наследуются от класса Point , то и их мы можем помещать в этот массив. Получается, каждую фигуру, которая есть в массиве figures мы можем рассматривать как объект класса Point . В этом и заключается полиморфизм: неизвестно, к какому именно классу принадлежат находящиеся в массиве figures объекты, но поскольку все объекты внутри этого массива принадлежат одному базовому классу Point , то все методы, которые применимы к классу Point также и применимы к его классам-наследникам.


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


Полный код примера:

Import java.util.ArrayList; class Main { /** * Именно в этом месте запускается программа */ public static void main(String args) { //ArrayList - Это специальная структура данных в java, // позволяющая хранить объекты определенного типа в массиве. ArrayList figures = new ArrayList(); //добавляем три разных объекта в массив figures figures.add(new Point()); figures.add(new LineSegment(133)); figures.add(new Triangle(10, 17, 55)); for (int i = 0; i

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

Объекты в ООП — это объекты реального мира

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

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

В операции снятия денег через банкомат участвуют 3 объекта : «клиент Иванов», «банкомат на Тверской» и «счет № 66579801», который открыт в данном банке для Иванова. Подойдя к банкомату и засунув свою карточку, объект «клиент Иванов» посылает банкомату сообщение «Начать работу». Получив такое сообщение, банкомат выводит на экран какую-нибудь информацию и запрашивает код доступа, т.е объект «банкомат на Тверской» посылает сообщение объекту «клиент Иванов» — «Сообщить идентификационный код». Если идентификация прошла успешно, «клиент Иванов» просит выдать ему 1000 рублей. Он посылает сообщение об этом банкомату, а тот в свою очередь объекту «счет № 66579801». Приняв это сообщение объект «счет № 66579801» проверяет есть ли у него 1000 рублей, и, если есть, пересылает разрешение на снятие денег, одновременно уменьшая свой баланс на соответствующую сумму. Банкомат передает деньги и на этом процедура заканчивается.

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

Описание в виде объектов позволяет определить различные компоненты системы. Те же самые объекты — «счет № 66579801» и «клиент Иванов» — будут учавствовать в другой операции при которой клиент приходит в отделение банка для снятие или зачисления денег на свой счет.

Приведенная ситуация является ярким примером сущности понятия «объект в ООП «. Сложно дать четкое определение этому понятию, приведу цитату этого определения Ивара Якобсона:

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

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

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

Состояние объекта в ООП

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

Состояние объекта характеризуется текущим значением его атрибутов . В нашем примере у счета есть атрибут -баланс. В простейшем случае он отражается числом — количеством рублей и копеек на счету. Операция снятия или зачисления на счет изменяет баланс и атрибут объекта «счет № 66579801». У объекта «банкомат на Тверской» есть несколько атрибутов. Количество денег в банкомате может характеризоваться числом. Состояние «включен» или «выключен» и состояние «готов или не готов к принятию запроса» — логическим значением.

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

Идентификация объектов в ООП

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

На самом деле существует два вопроса: равны ли два объекта или тождественны.

Обычно для идентификации применяются специальные атрибуты объектов — идентификаторы. Например, для объекта «счет № 66579801» идентификатором является его атрибут «номер счета», который является уникальным (соблюдается требование предметной области).

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

Интерфейс объекта в ООП

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

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

В нашем примере у объекта «счет № 66579801» есть следующие методы — «снять деньги со счета» и «положить деньги на счет». Эти два метода и составляют интерфейс объекта. У объекта «клиент Иванов» имеется метод «Сообщить свой код». А у объекта «банкомат на Тверской » есть методы «начать работу», «принять деньги», «выдать деньги».

У объекта «счет № 66579801» есть еще один атрибут «баланс». Является ли он частью интерфейса объекта? Интерфейс — это внешнее описание объекта. При разработке банковской системы и, в частности, объекта «счет», мы решаем вопрос: является ли баланс необходимой информацией для других объектов? Очевидно, что является. Тогда нам нужно ответить на еще один вопрос: что именно нужно другим объектам? Остаток денег на счете. В таком случае необходимо добавить еще один метод «сообщить остаток денег на счете» к объекту «счет» , и его интерфейс будет теперь состоять из трех методов.

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

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

Время жизни объекта в ООП

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

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

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

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

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

Композиция объектов в ООП

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

В следующей статье будут рассмотрены классы в ООП, как способ описания структуры и поведения объектов.

Последние материалы раздела:

"Андроид": установка приложений на карту памяти

Большинство владельцев устройств на Андроид рано или поздно сталкиваются с проблемой нехватки внутреннего пространства для хранения файлов ....

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

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

Разблокировать Bootloader HTC
Разблокировать Bootloader HTC

Из данной инструкции вы узнаете как разблокировать загрузчик (unlock bootloader) на смартфонах HTC при помощи официального способа. Есть еще один...