Глава 7. Объектно-ориентированное программирование
В объектно-ориентированном программировании (ООП) раз-личают три вида модели проблемной области: объектную, динамическую и функциональную.
Объектная модельпоказывает статическую структуру проблемной области, для которой разрабатывается система. Сначала определяются классы объектов, затем зависимости между объектами, включая агрегацию. Для упрощения структуры классов используется наследование. Объектная модель должна содержать краткие комментарии на естественном языке.
Динамическая модельпоказывает поведение системы, в особенности последовательность взаимодействий ее компонентов (объектов). Сначала готовятся сценарии типичных сеансов взаимодействия с системой, затем определяются внешние события, отражающие взаимодействие системы с внешним миром; после этого строится диаграмма состояний для каждого активного объекта, на которой представлены образцы событий, получаемых и порождаемых системой, а также действий, выполняемых ею. Построенные диаграммы состояний сравниваются между собой, чтобы убедиться в их непротиворечивости.
Функциональная модельпоказывает функциональный вывод значений безотносительно к тому, когда они вычисляются. Сначала определяются входные и выходные значения системы как параметры внешних событий. Затем строятся диаграммы потоков данных, показывающие как вычисляется каждое выходное значение по входным и промежуточным значениям. Диаграммы потоков данных выявляют взаимодействие с внутренними объектами системы, которые служат хранилищами данных в периоды между сеансами работы системы. В заключение определяются ограничения и критерии оптимизации.
Каждая модель хорошо подходит к одному из перечисленных систем:
- системы пакетной обработки— обработка данных производится один раз для каждого набора входных данных;
- системы непрерывной обработки — обработка данных производится непрерывно над сменяющимися входными данными;
- системы с интерактивным интерфейсом— системы, управляемые внешними воздействиями (обычно пользователем);
- системы динамического моделирования - системы, моде-лирующие поведение объектов внешнего мира;
-
системы реального времени - системы, в которых пре-
обладают строгие временные ограничения;
- системы управления транзакциями — системы, обеспе-чивающие сортировку и обновление данных; они имеют кол-лективный доступ. Типичной системой управления транзакциями является СУБД коллективного пользования.
Проектируя систему одного из вышеперечисленных типов, необходимо использовать соответствующую архитектуру. Во время разработки архитектуры программного обеспечения необходимо предусмотреть поведение каждого объекта, компонента и всей системы в пограничных ситуациях: инициализации, терминации и обвале.
Инициализация. Перед тем, как начать работать, система (компонент, объект) должна быть приведена в фиксированное начальное состояние: должны быть проинициализированы все константы, начальные значения глобальных переменных и параметров, задачи и, возможно, сама иерархия компонентов. Во время инициализации, как правило, бывает доступна лишь часть возможностей системы.
Терминациясостоит в освобождении всех внешних ресурсов, занятых задачами системы.
Обвал — это незапланированная терминация системы. Обвал может возникнуть в результате ошибок пользователя, нехватки ресурсов, или внешней аварии. Причиной обвала могут быть и ошибки в программном обеспечении системы.
На этапе программирования объектная модель уточняется и пополняется, в нее вводятся внутренние (вспомогательные) классы. Новые внутренние классы не имеют соответствий в реальном мире. Они связаны с программированием и могут существенно его упростить.
Во многих случаях бывает полезным внести некоторые изменения в структуру объектной модели. Эти изменения сводятся к введению дополнительных классов и к перераспределению операций между классами. При распределении операций по классам руководствуются соображениями:
- если операция выполняется только над одним объектом, то она определяется в классе, экземпляром которого является этот объект;
- если аргументами операции являются объекты разных классов, то ее следует поместить в класс, к которому принадлежит результат операции;
— если аргументами операции являются объекты разных классов, причем изменяется значение только одного объекта, а значения других объектов только читаются, то ее следует поместить в класс, к которому принадлежит изменяемый объект;
- если классы вместе с их зависимостями образуют звезду с центром в одном из классов, то операцию, аргументами которой являются объекты этих классов, следует поместить в центральный класс.
Реализация управлениясистемы связана с реализацией ее динамической модели. Известны три подхода к реализации динамической модели:
— процедурное управление — традиционный способ реализации динамической модели; ему соответствует определенный фрагмент программы;
— управление через события - это явная реализация конечного автомата; хорошо реализуется визуальным програм-мированием;
- использование параллельных независимых задач.
Уточняя определения классов и операций, надо постараться увеличить степень наследуемости: чем больше классов находятся в отношении наследования, тем меньше функций, реализующих операции этих классов, необходимо будет запрограммировать.
Для увеличения степени наследуемости требуется:
— перестроить классы и операции;
- выявить одинаковые (или взаимнооднозначно соответствующие) операции и атрибуты классов и определить для этих классов абстрактный суперкласс;
— использовать делегирование операций, когда наследование семан-тически некорректно,
.Иногда одна и та же операция бывает определена в нескольких классах, что позволяет ввести общий суперкласс для этих клас-сов, в котором, и реализуется эта операция.
Но чаще операции в разных классах бывают похожими, но не одинаковыми. В таких случаях нужно попытаться внести несущественные изменения в определения этих операций, чтобы они стали одинаковыми, т.е. имели одинаковый интерфейс и семантику.
При этом можно использовать следующие приемы:
- если операции имеют одинаковую семантику, но разное число формальных параметров, то можно добавить отсутствующие параметры, но игнорировать их при выполнении опе-рации; например, операция обрисовки изображения на мо-нохромный монитор не требует параметра «цвет», но его можно добавить и не принимать во внимание при выполнении операции;
- некоторые операции имеют меньше параметров потому, что они являются частными случаями более общих операций; такие операции можно не реализовывать, сведя их к более общим операциям с соответствующими значениями параметров; например, добавление элемента в конец списка есть частный случай вставки элемента в список;
- одинаковые по смыслу свойства или операции разных классов могут иметь разные имена; их можно переименовать и перенести в класс, являющийся общим предком рассматриваемых классов;
- операция может быть определена не во всех классах неко-торой группы классов; можно тем не менее вынести ее в их общий суперкласс, переопределив ее в подклассах как пустую там, где она не нужна.
В основе объектно-ориентированного программирования лежит идея объединения в одно целое структуры данных и действий (называемых методами), которые производятся над этими данными. При таком подходе организация данных и программная реализация методов оказываются гораздо сильнее связаны, чем при традиционном программировании.
Объектно-ориентированное программирование базируется на трех основных понятиях: инкапсуляции, наследовании, полиморфизме.
Инкапсуляция.— это комбинирование данных с процедурами и функциями, которые манипулируют этими данными. В результате получается новый тип данных — объект.
Наследование — это возможность использования уже определенных объектов для построения иерархии объектов, производных от них. Каждый из «наследников» наследует описания данных «прародителя» и доступ к методам их обработки.
Полиморфизм - это возможность определения единого по имени действия (процедуры или функции), применяемого од-новременно ко всем объектам иерархии наследования, причем каждый объект может «заказывать» особенность реализации этого действия над «самим собой».
Объектно-ориентированный стиль программирования может заметно упростить написание сложных программ, придать им гибкость.
Программы в этом случае получают такие дополнительные свойства, как:
- повторная используемость;
- расширяемость;
- устойчивость к неправильным данным;
- системность.
Программа обладает свойством системности, если она применима в качестве обобщенного оператора при «крупноблочном программировании».
Крупноблочное программирование — это систематическое использование ранее разработанных крупных программных единиц (таких, как классы, подсистемы или модули) при разработке новых программных систем.
Следующие рекомендации могут помочь разрабатывать клас- сы, обладающие свойством системности:
- методы должны быть хорошо продуманы;
- методы должны быть понятны всем, кто их прочитает;
- методы должны быть легко читаемы;
- имена методов (компонентов) должны быть такими же, как и в модели;
- методы должны быть хорошо документированы;
- спецификации методов должны быть доступны.
В объектно-ориентированном программировании объектом можно назвать все, что может иметь имя и может быть рассмот- рено как одно целое.
В качестве примера объекта можно привести: комбинацию кода и данных, которую можно рассматривать как одно целое, элемент управления, графический элемент, рисунок, метку, форму и пр.
Каждый объект определен классом (class).
Классиспользуется для создания объектов и определяет их характеристики. Например, объект, известный как элемент управления, не существует, пока он не нарисован на форме.
Когда создается объект, создается копия, или экземпляр (instance) класса, который он представляет. Затем уточняются другие его характеристики. Все объекты создаются как идентичные копии своих классов. Например, каждый объект «Кнопка управления» является экземпляром класса «Command Button», a «Элемент управления списком» представляет собой экземпляр класса «List Box». Объекты одного класса используют общий набор характеристик и способностей (свойств, методов и событий).
Свойства индивидуальных объектов можно изменять. Каждому объекту присваивается свое имя. Объекты можно по отдельности заблокировать и разблокировать, поместить в разные места на форме и т.д.
Визуальные инструментальные средства разработки программ предоставляют инструменты, позволяющие строить свои объекты или комбинировать их из различных источников, включая другие приложения, поддерживающие OLE технологию. Последнее сохранит время разработчика приложения, так как ему не при- дется писать код, воспроизводящий все функциональные возможности объектов другого приложения.
Объекты обладают свойствами, событиями и методами.
Свойстваотображают некоторые атрибуты объекта, методы - его действия, а события — это реакции объекта. Индивидуальные свойства объекта можно установить (изменить) во время выполнения программы или во время разработки приложения. В последнем случае лучше использовать окно Properties (Свойств), что позволяет вообще не писать никакого кода.
Методы могут воздействовать на значения свойств. В прог- рамме метод вызывается по имени, например, object.method (имя объекта + название метода).
События инициируются, когда изменяются некоторые свойства объекта. Событие можно вызвать щелчком или дви-жением «мыши», нажатием клавиши, из программы и пр. Со-бытия вызывают такие действия, как открытие / закрытие формы, получение объектом фокуса и пр.
Некоторые объекты могут содержать другие объекты. Удобство использования объектов в качестве контейнеров (containers) для других объектов заключается в том, что можно ссылаться на контейнер в коде для уточнения, используемого объекта. В частности, контейнером объектов может быть форма, которая сама является объектом.
Наиболее часто формы используются для создания интер- фейса приложения, но они также являются объектами, которые можно вызывать из других модулей приложения. Формы тесно
связаны с модулями классов. Главное различие между ними заключается в том, что формы могут быть видимыми объектами, тогда как модули не имеют видимого интерфейса.