Файл: История и развитие методологии объектно-ориентированного программирования. Сферы применения (Развитие методологии объектно-ориентированного программирования).pdf
Добавлен: 28.03.2023
Просмотров: 452
Скачиваний: 3
СОДЕРЖАНИЕ
1. Развитие методологии объектно-ориентированного программирования
1.2 Структурное программирование
1.3 Объектно-ориентированное программирование
2. Реализация объектно-ориентированного программирования
2.1 Объектно-ориентированное программирование в языке C++
2.2 Объектно-ориентированное программирование в языке Objective-C
3.1 Обзор и анализ предметной области
3.2 Проектирование классов программы
3.4 Проектирование интерфейса и алгоритмов программы
Таким образом, структурное программирование позволяет разделить алгоритм на небольшие блоки. Эта стратегия была очень популярной в начале 1980-х годов. Однако с ростом сложности задач структурное программирование приводило к снижению качества кода, вследствие чего разработчикам требовалось писать все больше функций, которые очень редко могли использоваться в других программах. Многие программисты увидели в объектно-ориентированном программировании потенциальное решение возникшей проблемы. С одной стороны, Smalltalk использовали почти все более-менее сложные системы. С другой – использование виртуальных машин повышало требования к ресурсам. Smalltalk был первым широко распространенным объектно-ориентированным языком программирования. Здесь понятие класса стало основообразующей идеей для всех остальных конструкций языка (то есть класс в Смолтоке является примитивом, посредством которого описаны более сложные конструкции).
В 1983-м году появились сразу два языка, на которые повлияли языки Си и Smalltalk, а также структурный подход. Это были Objective-C и C++, которые пытались избавиться от необходимости повторного использования кода. Оба языка активно задействовали новую, объектно-ориентированную парадигму, быстро ставшую популярной.
1.3 Объектно-ориентированное программирование
Выбор методологии для создания программы до появления языков четвертого поколения учитывал размеры программ, которые обычно были небольшими. В небольших программах наиболее распространенным оператором обычно является оператор присваивания. Однако в больших программах (более 10000 строк) наиболее распространенным оператором обычно является вызов процедуры подпрограммы. Обеспечение правильной передачи параметров в правильную подпрограмму становится серьезной проблемой. Концепция объектно-ориентированного проектирования заключалась в определении всех классов (и связанных с ними отношений и поведения), которые имеют отношение к решаемой проблеме.
Несмотря на то что структурирование программы и использование иерархической модели может помочь в проектировании некоторого программного обеспечения, для ряда больших программ объективно-ориентированный подход, как оказалось, является более гибким, поскольку разделяет программу на набор модулей, каждый из которых управляет своими собственными данными, алгоритмами или устройствами, но доступ к ним возможен только при первом указании именованного доступа к объекту класса модуля. Вместо того, чтобы полагаться на схему иерархии структурного программирования, объектно-ориентированному программированию необходим набор ссылок, чтобы проследить, какие модули или классы доступны из других мест [5.].
Состояние объекта в объектно-ориентированном языке является в основном внутренним для самого объекта. Каждый объект включает в себя набор функций и процедур, с помощью которых можно получить доступ и изменить локальное состояние. Они называются методами, но похожи на обычные процедуры и функции, за исключением того, что они могут автоматически получать доступ к данным объекта (в отличие от «внешнего мира») и, следовательно, могут рассматриваться как содержащие неявный параметр, представляющий сам объект.
Объекты могут быть объявлены путем создания шаблона для локального состояния и методов. Этот шаблон называется классом, и по сути он похож на тип данных. Действительно, во многих объектно-ориентированных языках класс является типом и включается в систему типов языка более или менее стандартными способами. Затем объявляются объекты определенного класса точно так же, как переменные определенного типа объявляются в языке, таком как Си или Паскаль. Говорят, что объект является экземпляром класса.
Центральным понятием объектно-ориентированного программирования является объект, который становится своего рода модулем, содержащим данные и подпрограмму. Объект – это самодостаточная сущность, которая имеет внутреннее состояние (содержащиеся в нем данные) и может отвечать на сообщения (обращения к его методам). Например, объект записей студента имеет состояние, состоящее из сведений обо всех зарегистрированных студентах. Если ему отправляется сообщение, в котором говорится о добавлении сведений о новом ученике, он отвечает, изменяя свое состояние. Если будет отправлено сообщение о том, что оно должно быть напечатано, оно ответит распечаткой списка сведений обо всех зарегистрированных студентах.
Подход объектно-ориентированного программирования к разработке программного обеспечения должен начинаться с определения объектов, вовлеченных в проблему, и определения сообщений, на которые эти объекты должны отвечать. В результате получается набор объектов, каждый со своими данными и собственным набором обязанностей. Объекты взаимодействуют, посылая сообщения друг другу [7.].
ООП демонстрирует следующие свойства: абстракция данных, инкапсуляция, наследование и полиморфизм.
Абстракция данных – это методология, которая позволяет скрывать фоновые данные от внешнего мира, предоставляя только важную информацию о том или ином объекте. Абстракция данных упрощает сложную реальность, моделируя классы, соответствующие задаче. Абстракция также достигается с помощью композиции. Например, класс, описывающий автомобиль, будет состоять из двигателя, коробки передач, руля и многих других компонентов. Чтобы создать этот класс, не нужно знать, как различные компоненты работают внутри, а только то, как взаимодействовать с ними, то есть отправлять им сообщения, получать от них сообщения и, возможно, как взаимодействуют различные объектами, составляющие класс, друг с другом.
Инкапсуляция – это возможность объединять код и данные в одном месте и скрывать эти данные от внешнего воздействия. Иными словами, это такое объединение внутри класса полей и методов, при котором доступ к полю возможен только путем вызова соответствующего метода. При идеальном выполнении принципа инкапсуляции поля класса могут быть только личными (использоваться только методами данного класса).
Наследование – это возможность определения для базового класса (предка) иерархии производных классов (наследников), в каждом из которых доступны элементы базового класса (их описание становится частью описания производного класса). Иначе говоря, наследование – механизм, посредством которого класс может наследовать элементы другого класса и добавлять к ним свои элементы.
Как правило, базовый класс является общим, производные – более специальными, конкретными. Естественно, у класса-наследника обычно больше полей и методов, чем у класса-предка, так как при наследовании обычно добавляются новые элементы.
Если имеется иерархия классов, то можно рассматривать защищенные (protected) элементы класса, которые доступны для методов своего класса и его наследников.
Одиночное наследование – это случай, когда каждый производный класс может наследовать только от одного базового класса, тогда как множественное наследование – это случай, когда класс может наследовать от двух или более базовых классов. В современных объектно-ориентированных языках, таких как Java и C++, предусмотрено множественное наследование.
Полиморфизм – это механизм, который позволяет объектам разных типов по-разному реагировать на один и тот же вызов функции. Перегрузка и шаблоны функций могут рассматриваться как примитивные полиморфизмы, поскольку решение о вызове конкретной функции принимается во время компиляции, а не во время выполнения. Во время компиляции точная природа некоторых объектов не может быть определена. Полиморфизм – это способность идентифицировать определенные аспекты, общие для нескольких типов данных, и писать код, который одинаково хорошо работает со всеми из них, игнорируя различия в ситуациях, не имеющих значения [2.].
Как структурное программирование, так и ООП требуют элементарного понимания концепций программирования и порядка выполнения инструкций программы. Циклы, условные операторы и переменные являются понятиями, которые необходимо знать вне зависимости от того, какой из подходов используется. В таблице 1 приведены основные различия между объектно-ориентированным и структурным программированием.
Таблица 1
Различия между структурной и ООП-парадигмой
|
Структурное программирование |
Объектно-ориентированное программирование |
|
Нисходящий подход |
Восходящий подход |
|
Фокус на алгоритме и инструкциях |
Фокус на объектной модели |
|
Программа делится на подмодули, функции, процедуры |
Программа организована с помощью ряда классов и объектов |
|
Функции не зависят друг от друга |
Классы могут образовать иерархию |
|
Данные и функции рассматриваются как отдельные объекты |
Данные и функции – единое целое |
|
Повторное использование методов невозможно |
Возможно повторное использование методов |
|
Используется вызов функции |
Сообщения передаются объектам |
|
Абстракция функций |
Абстракция данных |
|
Главное – алгоритм |
Главное – данные |
|
Инкапсуляция отсутствует |
Данные и функциональные возможности – единая сущность |
|
Ключевое отношение – между программистом и программой |
Ключевое отношение – между программистом и пользователем |
2. Реализация объектно-ориентированного программирования
2.1 Объектно-ориентированное программирование в языке C++
C++ был написан Бьерном Страуструпом в Bell Labs в 1983-1985 гг. C++ является расширением Си. До 1983 года Бьерн Страуструп добавил функции в Си и сформировал то, что он назвал «Си с классами». Он объединил использование классов и объектно-ориентированных функций из языка Simula с мощью и эффективностью языка Си.
В C++ (как и во многих других объектно-ориентированных алгоритмических языках) вводится новый тип данных – класс. Переменная типа класс называется объектом. Иногда объект называют также экземпляром класса. Формально описание класса напоминает структуру, но класс, кроме полей (переменных), содержит методы, которые задают допустимые действия над полями класса. Общее название для полей и методов – элементы класса.
В листинге 1 дается простейшее описание класса на языке С++.
Листинг 1. Описание класса в языке C++
class имя_класса {
private:
описание личных элементов класса
public:
описание общих элементов класса
};
Под личными элементами класса (private) понимаются такие элементы, которые могут использоваться только методами своего класса. К общим элементам класса (public) доступ разрешен в любом месте программы. Существуют и другие способы доступа к элементам класса.
Поля класса описываются внутри класса как обычные переменные. Методы – это функции, которые можно применять к полям. Считается хорошим стилем программирования, что внутри класса методы задаются своими прототипами. Вне класса (ниже его описания) приводится полное описание метода. Очень короткие методы можно полностью описывать внутри класса.
Как правило, поля являются личными элементами класса, т. е. доступ к полям разрешен только внутри методов класса. Это положение можно рассматривать как простейшую формулировку принципа инкапсуляции.
Если внутри класса метод описан прототипом:
тип_результата имя_метода (список типов параметров),
то при полном описании вне класса метод имеет заголовок:
тип_результата имя_класса::имя_метода (список параметров),
т. е. в заголовке перед именем метода указывается имя класса (через знак «::»).
Существуют особые методы класса: конструкторы и деструкторы [10.]. Назначение конструктора заключается в создании экземпляра класса и инициализации его полей. Имя конструктора совпадает с именем класса. Конструктор никогда не вызывается явно, его вызов осуществляется компилятором в момент создания экземпляра класса.
Деструктор вызывается для уничтожения экземпляра класса. Имя деструктора образуется как ~имя_класса. Деструктор может вызываться в программе явно или (что происходит обычно) его вызов обеспечивается компилятором в момент уничтожения экземпляра класса.
Наличие конструктора и деструктора для любого класса обязательно; при их отсутствии компилятор автоматически создает стандартные варианты конструктора и деструктора.
Экземпляры класса могут создаваться автоматически или динамически. Уничтожение автоматически созданных экземпляров классов происходит также автоматически при завершении выполнения блока функции, в котором они были определены. Определение (описание) автоматического экземпляра класса может встречаться в любом месте функции и имеет вид:
имя_класса имя_экземпляра(параметры конструктора);