Файл: История и развитие методологии объектно-ориентированного программирования. Сферы применения.pdf
Добавлен: 14.05.2023
Просмотров: 425
Скачиваний: 2
СОДЕРЖАНИЕ
Часть I Объектно-ориентированное программирование
Глава 1 Эволюция методологий программирования
1.1 Поколения языков программирования
1.1.1 Начало начал, или первое поколение языков программирования
1.1.2 Развитие алгоритмических абстракций. Второе поколение языков программирования.
1.2. ЗАРОЖДЕНИЕ ОБЪЕКТНОЙ МОДЕЛИ
1.2.1 Объектные языки программирования
1.2.2 Объектно-ориентированные языки
1.2.3 Объектно-ориентированный анализ, дизайн и проектирование
1.3 Парадигмы программирования
Глава 2 Составные части объектного подхода
3.1 Что такое объект с точки зрения ООП
3.3.1 Классификация методов объектов
3.3.3 Связь объектов и автоматов, активные и пассивные объекты
2.7 Сохраняемость
Любой объект или данные в программной системе существуют во времени и пространстве (памяти ЭВМ). Одни объекты существуют только как промежуточные результаты вычисления выражения, другие могут вообще пережить программу, оставаясь сохраненными в базе данных. Этот спектр подразделяется на следующие уровни:
• Промежуточные результаты вычислений выражений
• Локальные переменные и объекты в блоках, а также, при вызове процедур и функций (как правило эти данные существуют на стеке)
• Статические переменные классов, а также, глобальные переменные и объекты в динамической памяти
• Данные, сохраняемые между сеансами выполнения программы
• Данные, сохраняемые при переходе на другую версию программы.
• Данные, переживающие программу
В языках программирования традиционно можно встретить поддержку верхних трех уровней этого спектра. Три нижних уровня, как правило, входят в компетенцию баз данных. Из этого правила существуют интересные исключения.
Бывают случаи, когда зоны влияния баз данных и языков расширяются за пределы их традиционных сфер ответственности. Такими примерами служат объектные базы данных, которые появились в результате союза объектных концепций и традиционных баз данных. Следующим примером могут служить языки, имеющие встроенную поддержку сохраняемости (Java5). С проблемой сохраняемости связана не только проблема сохранения данных (состояния объектов), но и проблема сохранения информации о структуре этих данных, что при сохранении объектов приводит к сохранению классов в объектно-ориентированных базах данных. Серьезной проблемой становится задача миграции данных в ООБД при изменениях в структурах их классов. Не смотря на развитие теории объектно-ориентированных баз данных, традиционные реляционные базы данных продолжают занимать лидирующее положение на рынке систем хранения данных. Этому служат множество причин:
• Реляционные базы данных обладают значительной универсальностью, хранящаяся в них информация может быть использована различными по своей идеалогии программными системами: как объектно-ориентированными, так и написанными с использованием процедурного или другого подхода.
• Реляционные базы данных обладают хорошими характеристиками в плане производительности, надежности и транзакционности.
• В мире уже накоплено огромное количество информации в реляционных базах данных, и, зачастую, крупные базы переживают не одно поколение использующих их программных систем. Для обеспечения взаимодействия объектно-ориентированных си- стем и реляционных баз данных разработано множество средств отображения объектно-ориентированных структур на реляционные базы данных для обеспечения сохраняемости (так называемые OR-mappers). Существуют библиотеки, предоставляющие объектно-ориентированный интерфейс для манипуляций с данными в RDBMS. Кроме сохранения объектов во времени, актуальным является вопрос возможности транспортировки (переноса) объектов из одной среды исполнения в другую, возможно находящуюся на удаленном компьютере. Речь идет, прежде всего, о построении распределенных систем. Для решения этой задачи могут применяться специальные технологии на подобие CORBA, Microsoft COM+, SOAP, Java RMI. Итак, можно привести следующее определение сохраняемости (по Бучу): Сохраняемость — это способность объекта существовать во вре- мени, переживая породивший его процесс, и (или) в пространстве, перемещаясь из своего первоначального адресного пространства. На этом мы закончим рассмотрение основных принципов объектно-ориентированного программирования и перейдем к рассмотрению природы и основных свойств объектов, как кирпичиков для построения информационных систем.
Глава 3 Объекты
3.1 Что такое объект с точки зрения ООП
Что есть объект? Как объекты реального мира связаны с объектами в объектно-ориентированной системе? Какими свойствами обладают объекты в программировании? И, наконец, как объекты взаимодействуют между собой? Что такое роль и как это понятие связано с объектом? Все эти вопросы могут возникнуть у человека, начинающего изучать объектный подход в программировании. В данной части нашего повествования мы попытаемся дать ответы на эти вопросы и выработать понимание того, что такое объект в объектно-ориентированной системе. Понятие объекта выделено человеком уже довольно давно. Еще древние философы пытались дать ответ на вопрос, что же такое объект. Есть замечательный пример про ребенка и мяч, который приведен в книге Буча [1, §3]. Этот пример показывает, как эволюционирует понятие объекта в сознании человека. Способностью к распознаванию объектов физического мира человек обладает с самого раннего возраста. Ярко окрашенный мяч привлекает внимание младенца, но, если спрятать мяч, младенец, как правило, не пытается его искать: как только предмет покидает поле зрения, он перестает существовать для младенца. Только в возрасте около года у ребенка появляется представление о предмете: навык, который незаменим для распознавания. Покажите мяч годовалому ребенку и спрячьте его: скорее всего, ребенок начнет искать спрятанный предмет. Ребенок связывает понятие предмета с постоянством и индивидуальностью формы независимо от действий, выполняемых над этим предметом. По мере своего развития и обучения, человек учится мыслить не только в терминах реальных и осязаемых объектов, но и в терминах абстрактных сущностей, которых может и не существовать в реальном мире. С точки зрения человека объектом может быть: • осязаемый и (или) видимый предмет;
• нечто, воспринимаемое мышлением;
• нечто, на что направлена мысль или действие.
Термин объект в контексте программирования информационных систем впервые появился в языке Simula, разработанном для моделирования окружающей действительности. В простейшем случае объекты выделяются на основе реальных сущностей в предметной области, к которой относится разрабатываемая программная система. Для более подробного рассмотрения понятия объекта читателю лучше обратиться к книге Буча[1]. Здесь же мы сформулируем и рассмотрим только основные ключевые идеи. При проектировании информационной системы с использованием объектного подхода разработчик выделяет объекты на основе их наиболее существенных характеристик в предметной области. В общем случае, программные объекты обладают далеко не полным набором свойств и характеристик в сравнении с моделируемыми ими объектами реального мира. Далеко не все объекты, существующие в информационной системе, имеют своих аналогов в реальном мире. Зачастую, в процессе проектирования и разработки появляется большое количество вспомогательных объектов, призванных обеспечить среду существования для бизнес-объектов. Понятия бизнес-логики и бизнес-объекта служат для обозначения той части программной системы, которая непосредствен- но моделирует процессы реальной предметной области(задачи), для решения или автоматизации которой разрабатывается информационная система. Важным отличием объекта от экземпляра абстрактного типа данных является то, что объект обладает состоянием, поведением и уникальностью (идентичностью). Ниже приводится определение объекта по Бучу: Объект обладает состоянием, поведением и идентичностью; структура и поведение схожих объектов определяет общий для них класс; термины «экземпляр класса» и «объект» взаимозаменяемы. 3.2 Состояние Рассмотрим хрестоматийный пример из книги Буча [1, §3] иллюстрирующий работу автомата по продаже газированной воды. Поведение такого объекта состоит в том, что после опускания в не- го монеты и нажатия кнопки, автомат выдает выбранный напиток. Что произойдет, если сначала будет нажата кнопка выбора напитка, а потом уже опущена монета? Большинство автоматов при этом просто ничего не сделают, так как пользователь нарушил их основные правила. Другими словами, автомат играл роль (ожидание монеты), которую пользователь игнорировал, нажав сначала кнопку. Или предположим, что пользователь автомата не обратил внимание на предупреждающий сигнал «Бросьте столько мелочи, сколько стоит напиток» и опустил в автомат лишнюю монету. В большинстве случаев автоматы не дружественны к пользователю и радостно заглатывают все деньги. В каждой из таких ситуаций мы видим, что поведение объекта определяется его историей: важна последовательность совершаемых над объектом действий. Такая зависимость поведения от событий и от времени объясняется тем, что у объекта есть внутреннее состояние. Для торгового автомата, например, состояние определяется суммой денег, опущенных до нажатия кнопки выбора. Другая важная информация - это набор воспринимаемых монет и запас напитков. На основании этого Буч дает следующее определение: Состояние объекта характеризуется перечнем (обычно статическим) всех свойств данного объекта и текущими (обычно динамическими) значениями каждого из этих свойств. Одним из свойств торгового автомата является способность принимать монеты. Это статическое (фиксированное) свойство, в том смысле, что оно — существенная характеристика торгового автомата. С другой стороны, этому свойству соответствует динамическое значение, характеризующее количество принятых монет. Сумма увеличивается по мере опускания монет в автомат и уменьшается, когда продавец забирает деньги из автомата. В некоторых случаях значения свойств объекта могут быть статическими (например, заводской номер автомата), поэтому в данном определении использован термин «обычно динамическими». Перечень свойств объекта является, как правило, статическим, поскольку эти свойства составляют неизменяемую основу объекта. Мы говорим «как правило», потому что в ряде случаев состав свойств объекта может изменяться. Примером может служить робот с возможностью самообучения. Робот первоначально может рассматривать некоторое препятствие как статическое, а затем обнаруживает, что это дверь, которую можно открыть. В такой ситуации по мере получения новых знаний изменяется создаваемая роботом концептуальная модель мира. Все свойства имеют некоторые значения, причем, существенным является то, что эти свойства могут быть как простыми количественными характеристиками (иметь числа в качестве значений), так и ссылками на другие объекты. Если говорить об автомате, то количественной характеристикой является сумма опущенной в автомат мелочи. С другой стороны состояние автомата определяется также наличием напитков, которые являются самостоятельными объектами, отличными от торгового автомата (их можно пить, а автомат нет, и совершать с ними иные действия). В информационной системе тот факт, что объект имеет состояние, означает, что значения (количественные или ссылочные), образующие это состояние, должны где-то храниться. Как правило, эти значения хранятся в оперативной памяти, и, таким образом, объект занимает место в пространстве (памяти компьютера). 3.3 Поведение Объекты не существуют изолированно, а взаимодействуют друг с другом, реализуя поведение. Здесь уместно привести известную аллегорию про самолет: «Самолет представляет собой совокупность вещей, каждая из которых по отдельности стремиться упасть на землю, но вместе, во взаимодействии, они преодолевают эту тенденцию». Буч определяет поведение следующим образом: Поведение — это то, как объект действует и реагирует; поведение выражается в терминах состояния объекта и передачи сообщений. Иными словами, поведение объекта — это его наблюдаемая и проверяемая извне деятельность. Взаимодействие объектов может быть описано в терминах операций. Операцией называется определенное воздействие одного объекта на другой с целью вызвать соответствующие действия или реакцию. Например, в контракте нашей объектной реализации стека существуют операции push и pop, которые служат для управления стеком. Вместо концепции операций (уходящей своими корнями в процедурное прошлое), можно использовать объектно-ориентированную концепцию передачи и обработки сообщений. При этом мы говорим, что какой-нибудь объект может передать нашему стеку сообщение push или pop, а наш стек воспримет и обработает полученное сообщение. Можно сказать что операция — суть реакция на сообщение.
3.3. ПОВЕДЕНИЕ
В языках C++ и Java концепции передачи сообщений и операций реализуются через один и тот же механизм (вызов методов или функций- членов классов), поэтому, по своей сути, являются эквивалентными. Мы будем отдавать предпочтение концепции передачи сообщений. В самом деле, коль скоро мы говорим об инкапсуляции, как основном средстве объектно-ориентированного программирования, то совершенно естественным будет подход к дизайну классов на основе со- общений. При этом функциональный контракт класса (и его предков) определяет набор сообщений, которые объект способен воспринять, а реализация реакции объекта на полученное сообщение остается инкапсулированной внутри реализации иерархии классов к которой принадлежит объект. Реакция объекта на полученное сообщение (т.е. поведение объекта) зачастую зависит не только от самого сообщения (вызванного метода), но и от текущего состояния объекта. Например, если в автомат по продаже напитков опустить недостаточную сумму денег, то после выбора напитка, скорее всего, ничего не произойдет. Если же денег достаточно, то автомат выдаст требуемый напиток. Таким образом, реакция автомата на требование (сообщение) о выдачи напитка различна в зависимости от состояния параметра, определяющего текущую сумму мелочи, опущенной в автомат. Итак, поведение объекта определяется выполняемыми над ним операциями (переданными ему сообщениями) и его текущим состоянием. Причем, некоторые операции могут изменить внутреннее состояние объекта (или в терминах концепции сообщений, реакция на некоторые сообщения ведет к изменению состояния объекта). В результате мы подошли к следующему важному утверждению: Состояние объекта представляет суммарный результат его поведения.
3.3.1 Классификация методов объектов
Как уже было сказано, поведение объекта реализуется через методы его класса (или классов). Всего можно выделить пять видов методов (операций):
• Конструкторы Методы создания объекта и/или его инициализации
• Деструкторы Методы, освобождающие состояние и ресурсы объекта и/или разрушающие сам объект
• Селекторы Методы, считывающие но не меняющие состояние объекта
• Модификаторы Методы, способные изменить состояние объекта
• Итераторы Методы, позволяющие организовать доступ к частям объекта-контейнера в строго определенной последовательности.
Все эти виды имеют разную поддержку в объектно-ориентированных языках. Конструкторы и деструкторы дают контроль над процессами создания/уничтожения объектов, и, в большей степени являются «операциями». Селекторы и модификаторы являются наиболее часто вызываемыми методами объекта и могут использоваться как обработчики сообщений. Итераторы обычно стоят несколько обособленно, причем, зачастую для реализации итеративного доступа к контейнеру используются специальные объекты. Мы рассмотрим данный механизм когда будем углубленно изучать конкретные языки. В языке С++ конструкторы и деструкторы играют очень важную роль, так как в них, как правило, происходит выделение и высвобождение памяти под составные части объекта. Небрежное написание кода этих методов приводит к всевозможным проблемам связанным с падением производительности и утечкой ресурсов. Всегда нужно помнить об особенностях, связанных с конструкторами и деструкторами по умолчанию, конструктором копии и оператором присваивания (operator =). Не смотря на то, что средства поддержки механизмов создания и удаления объектов могут показаться относительно сложными для начинающих программистов на C++, эти средства предоставляют полный контроль за управлением памятью в информационной системе. Всегда можно предсказать когда объект будет создан, сколько ресурсов он займет и когда будет уничтожен. С этой точки зрения С++ позволяет писать максимально высокопроизводительные и надежные системы. Необходимо так же помнить, что конструкторы от одного аргумента в C++ используются для приведения типов. Кроме этого, в C++ присутствует языковой механизм защиты данных объекта в методах-селекторах. Так, функции-члены, которые являются селекторами, должны быть объявлены со спецификаторами до- ступа const. Это обеспечивает защиту данных (состояния) объекта от изменений внутри этих методов и позволяет вызывать эти функции на константных объектах. Для объявления встраиваемых функций используется спецификатор inline. Использование данного механизма может существенно увеличить производительность. Для С++ будет справедливым утверждение, что все методы — операции, но не все операции — методы: некоторые из них могут представляют собой свободные подпрограммы. Язык Java, в отличие от C++, будучи платформенно независимым и имеющий развитую систему безопасности, не предоставляет программисту средств управления памятью, выделяемой при размещения объектов. Этот язык имеет строгую систему типов и не имеет переопределяемых операторов, что существенно минимизирует риск связанный с небрежным написанием кода программ. Наличие сборщика. Мы не будем сейчас здесь заострять внимание на проблеме фрагментации памяти. Следует сказать, что современные компиляторы как C++, так и Java, во многом берут задачу оптимизации на себя и могут исправлять наиболее распространенные недостатки небрежно написанного кода программы мусора, с одной стороны, помогает справляться с проблемой утечки ресурсов; с другой стороны, не позволяет точно предсказать производительность Java приложений. В Java есть конструкторы, в том числе и конструкторы по умолчанию, но нет явных деструкторов. Для обеспечения операций клонирования в языке и языковой библиотеке есть специализированный механизм, а для освобождения ресурсов объекта перед удалением используется специализированный метод finalize(). Для высвобождения ресурсов при работе распределенных Java приложений, в частности основанных на использовании Java RMI, существует механизм удаленной сборки мусора. Следует упомянуть, что в Java нет свободных подпрограмм (функций). Для реализации эквивалентной функциональности можно (и нужно) пользоваться статическими методами классов-утилит5. Желательно использовать подобный подход и в C++, так как он способствует более легкой расширяемости программного продукта. К сожалению, в Java нет средств языковой поддержки защиты данных при написании функций-селекторов. В таких классах стандартной библиотеки Java, как String, Integer, Float и подобных, попросту отсутствуют методы позволяющие изменить содержимое объекта.
3.3.2 Роли объектов
Совокупность всех методов и свободных процедур, относящихся к конкретному объекту, образуют протокол этого объекта. Протокол, таким образом, определяет поведение объекта, охватывающее все его статические и динамические аспекты. Коль скоро мы стремимся не использовать свободных функций, то будем дальше считать, что протокол объекта образуется только совокупностью методов классов, к которым объект принадлежит. Для сложных объектов очень полезным бывает разделение контракта на несколько отдельных абстракций (интерфейсов) с целью выделения различных, независимых с точки зрения групп внешних объектов, областей ответственности. Обычно такая ситуация идентифицируется следующим образом: если две разные абстракции используют непересекающиеся подмножества методов объекта, то следует эти подмножества выделить в отдельные интерфейсы, которые реализует класс этого объекта. В этом случае мы будем говорить, что объект играет разные роли по отношению к этим абстракциям, его использующим. Можно сказать, что состояние и поведение объекта определяют исполняемые им роли, а те, в свою очередь, необходимы для выполнения ответственности данной абстракции. Как правило, проектирование системы абстракций начинается с идентификации ролей, которые может играть тот или иной объект в системе. В последующем, роли всех объектов в системе сводятся в иерархические структуры и группируются по пакетам и подсистемам.
3.3.3 Связь объектов и автоматов, активные и пассивные объекты
Так как большинство интересных объектов обладает состоянием и их поведение зависит от предыстории, то многие объекты естественным образом могут быть представлены в виде конечных автоматов. 7 В объектно-ориентированном дизайне данный принцип носит название принципа сегрегации (разделения) интерфейсов Еще раз разъясним ситуацию: классы и интерфейсы являются абстракциями; объект является экземпляром класса, который принадлежит к иерархии классов и может реализовывать несколько интерфейсов. При этом, в итоге, объект будет принадлежать ко множеству абстракций, образованных его классом, его суперклассами, а также интерфейсами, которые реализуют его класс и суперклассы. Кроме того, вспоминая принцип параллелизма, мы приходим к пониманию сути активных и пассивных объектов. Активный объект имеет свой поток управления, а пассивный — нет. Активный объект в общем случае автономен, то есть он может проявлять свое поведение без воздействия со стороны других объектов. Пассивный объект, напротив, может изменять свое состояние только под воздействием других объектов. Таким образом, активные объекты системы - источники управляющих воздействий. Если система имеет несколько потоков управления, то и активных объектов может быть несколько. В последовательных системах обычно в каждый момент времени существует только один активный объект, например, главное окно, диспетчер которого ловит и обрабатывает все сообщения. В таком случае остальные объекты пассивны: их поведение проявляется, когда к ним обращается активный объект. В других видах последовательных архитектур (системы обработки транзакций) нет явного центра активности, и управление распределено среди пассивных объектов системы.