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

 

 

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

· выделении классов объектов;

· установлении характерных свойств объектов и методов их обработки;

· создании иерархии классов, наследовании свойств объектов и методов их обработки.

 

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

Объектный подход при разработке алгоритмов и программ предполагает:

· объектно-ориентированный анализ – анализ предметной области и выделение объектов, определение свойств и методов обработки объектов, установление их взаимосвязей;

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

 

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

 


Основные понятия объектно-ориентированного проектирования

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

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

Механизмы, поддерживаемые ООП, позволяют моделировать понятия предметной области более прямым и естественным путем.

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

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

Свойства — это простые переменные, которые описывают состояние объекта. Например, ширина, высота, цвет и т.п. – это свойства объекта.

Методы – это процедуры и функции, определяющие то, что объект умеет делать (вычислять). Например, объект может иметь процедуру для вывода какого-то текста на экран. Эта процедура и есть метод объекта.

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

Указанное объединение в едином объекте свойств, методов и событий называется инкапсуляцией.

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

Она представляет собой технику, при которой информация прячется внутри структуры.

Пример: рассмотрим объект – «кнопка». Такой объект должен обладать следующим минимальным набором:

Свойства:

1. Левая позиция (Х).

2. Верхняя позиция (Y).

3. Ширина.

4. Высота.

5. Заголовок.

Методы:

1. Создать кнопку.

2. Уничтожить кнопку.

3. Нарисовать кнопку.

События:

1. Кнопка нажата.

2. Заголовок кнопки изменен.

 

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

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


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

Наследование — это такое отношение между объектами, когда один объект повторяет структуру и поведение другого.

 

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

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

Типы верхних уровней ОО-иерархии, как правило, не имеют конкретных экземпляров объектов. Не существует, например, конкретного живого организма (объекта), который бы сам по себе назывался «Млекопитающее» или «Птица». Такие типы называются абстрактными. Конкретные экземпляры объектов имеют, как правило, типы самых нижних уровней ОО-иерархий: «крокодил Гена» — конкретный экземпляр объекта типа «Крокодил», «кот Матроскин» — конкретный экземпляр объекта типа «Кошка домашняя».

 

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

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

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

Еще одним основополагающим понятием ООП является полиморфизм.

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

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

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

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

 

 


2.2. Пример объектно-ориентированного проектирования

 

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

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

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

 

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

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

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

R - радиус круга;

X, Y - координаты центра круга;

Color - цвет круга.

Для того чтобы нарисовать этот круг на экране, нужна процедура, которую можно назвать Draw. Она будет изображать круг с заданными параметрами R, X, Y, Color.

Недостаток стандартного метода заключается в том, что данные в этом случае не являются взаимосвязанными. Предположим, что нужно нарисовать не один, а три круга (например, снеговика). При использовании стандартного метода программирования придется выбирать между двумя способами реализации этого приме­ра. Первый способ - завести для каждого круга свой набор параметров R, X, Y, Color, а затем вызывать процедуру Draw с каждым из этих наборов. Недостаток данного способа очевиден: если нужно рисовать много кругов, то понадобится большое количество переменных. Это приведет к тому, что программа станет очень громоздкой.

 

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

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

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

Сделать возможным изменение цвета для всех кругов, из которых состоит снеговик - процедура ChangeColor. Для ее выполнения будут необходимы два параметра: имя изменяемого объекта-круга и новый цвет, которым он будет закрашен.

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

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

 

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

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

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

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

Рис.2.4. Иллюстрация понятия инкапсуляции в ООП

 

Теперь приведенные рассуждения можно применить к рассматриваемому примеру с кругами.

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

Свойствами класса Round являются следующие:

• R - радиус круга;

• X, Y - координаты центра круга;

• Color - цвет круга.

Методы класса Round:

• Draw - рисует круг с заданными параметрами;

• Move - перемещает круг на определенное расстояние в выбранном направлении;

• ChangeColor - изменяет цвет круга.

 

Для того чтобы нарисовать снеговика, потребуются три объек­та-круга. Верхний из них можно назвать Head, средний - Body, a нижний - Foot. Все эти объекты принадлежат классу Round. Сле­довательно, все они имеют одинаковые свойства (R, X, Y, Color) и вызывают одинаковые методы (Draw, Move, ChangeColor) в ответ на одни и те же запросы.

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

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

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

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

Чтобы не выполнять подобную двойную работу, в ООП существует механизм наследования. Этот механизм реализуется путем создания иерархической структуры классов. Вначале создается класс Round, для которого описываются все свойства и методы. Он располагается в основании иерархической структуры. Затем создается еще один класс под названием Eyes, в котором описывается новый метод Blink, а все остальные свойства и методы остаются без изменений, т.е. класс Eyes наследует все свойства и методы Round и, в то же время, включает в себя дополнительный метод Blink. В иерархической структуре Eyes следует за классом Round, и в этом случае говорят, что Round является предком (или родительским классом) для Eyes. В свою очередь. Eyes является потомком (или дочерним классом) для Round.

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

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

Полиморфизм

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

Таблица 2.1

Наследование классом Eyes свойств и методов Round

    Round (раунд)   Свойства
R
X
Y
Color (Калар)
Методы
Draw (Дро)
Move (Мов)
ChangeColor
    Eyes (Айс)   Свойства
R
X
Y
Color
Методы
Draw
Move
ChangeColor
Blink (блинк)

 

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

 

Для реализации приведенных требований следует создать класс Rect (rectangle - прямоугольник), являющийся потомком Round, и применительно к нему Х и Y - это координаты выбранной вершины прямоугольника, а R — его длина (или ширина). Но в этом случае придется описать еще одно свойство для обозначения ширины (или длины). Очевидно, что при работе с подобными классами легко может возникнуть путаница в использовании свойств, и причина этого - узкая направленность класса Round, который ориентирован на работу только с определенной геометрической фигурой. Чтобы сделать Round более универсальным, т.е. пригодным для изображения большего числа геометрических фигур, следует изменить его свойства следующим образом. Вместо радиуса и координат центра нужно описать такие свойства:

 

Top - координата верхний границы фигуры;

Left - координата левой границы фигуры;

Height - высота фигуры;

Width - ширина фигуры.

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

 

Тор =80,

Left =20,

Height =40,

Width = 60.

 

Тогда правая граница равна Left + Width = 80, а нижняя – Тор - Height = 40.

Следовательно, данный прямоугольник имеет следующие координаты (первая координата - для горизонтальной оси, вторая - для вертикальной): А(20, 80), В(80, 80), С(20, 40), D(80, 40). На рис.2.5 изображен рассмотренный прямоугольник.

 

Рис.2.5. Построение прямоугольника по заданным вершине, высоте и ширине

 

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

Чтобы этого избежать, необходимо для Rect описать свой метод Draw. Тогда для объекта, принадлежащего классу Round, вызов Draw будет означать изображение на экране круга, а для объекта из Rect - прямоугольника. Т.е. методы с одним и тем же именем Draw отвечают за разные действия в зависимости от того, объекту какого класса необходимо выполнить рисование. Подобная ситуация в ООП носит название полиморфизма. Графическая интерпретация описанного примера полиморфизма в ООП приведена на рис. 2.6.

 

Рис. 2.6. Полиморфизм при вызове метода Draw объектами классов Rect и Round

 

Выводы

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

 

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

 

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

 

  1. Основными механизмами ООП являются:

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

Наследование — это такое отношение между объектами, когда один объект повторяет структуру и поведение другого.

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

 

 

 


Приложение 1