Назад Оглавление Вперед




3. Концепции объектно-ориентированного подхода к разработке больших программных систем.

    В настоящее время объектно-ориентированный подход является одним из быстро развивающихся направлений в проектировании систем. Примером могут являться объектно-ориентированный анализ - методология разработки систем, предложенная Йорденом, объектно-ориентированное проектирование, объектно-ориентированное программирование, реализованное в многочисленных компиляторах C++, Object Pascal, Borland Pascal, Smalltalk.

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

     инкапсуляция - такое свойство при котором объекты содержат описание атрибутов и действий одновременно,

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

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

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

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

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

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

    Рассмотрим эти особенности на следующем примере. Пусть разрабатывается библиотека подпрограмм для работы с матрицами. Пусть выбрано хранение в виде двумерного массива. При необходимости перехода к разреженному хранению придется изменять любое определение данных для обращения к библиотеке. Если же матрица определена как абстрактный тип данных с операциями: ⌠получить значение элемента■, ⌠изменить значение элемента■ и т.п., то изменение метода хранения матрицы не скажется на других частях программы. В программе не описываются переменные типа ⌠array [ 1..10 ] of integer■ и нет прямых обращений к элементам массива вида "A[i]".

    Объект, обладающий свойством инкапсуляции характеризуется следующими параметрами:

    Рассмотрим характерное описание объекта:

объект:

точка

атрибуты:

позиция на плоскости

методы:

создать

удалить

переместить в новую позицию

отобразить

стереть

объект:

прибор

атрибуты:

показания

методы:

снять показания

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

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

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

Рис. 3.1. Пример наследования свойств вида "является".

    Наследование вида "является" предполагает, что объект-наследник полностью включает в себя все свойства объекта-родителя.

    Другой вид наследования - сборочный, вида "состоит-из" можно продемонстрировать на примере автомобиля (рис. 3.2.)

    Рис. 3.2. Пример наследования свойств вида "состоит - из"

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

объект:

геометрическая фигура

атрибуты:

позиция на плоскости

методы:

создать

удалить

переместить в новую позицию

отобразить

стереть

объект:

прямоугольник

атрибуты:

высота

ширина

методы:

создать

отобразить

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

3.3 Полиморфизм

    Полиморфизм предполагает возможность одинакового именования разных действий. Эта особенность имеет два аспекта:

     возможность одинакового именования статических методов

     возможность одинакового именования динамических методов.

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

     Геометрическая фигура. нарисовать или

     Прямоугольник. нарисовать.

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

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

    1. стереть объект в текущей позиции,

    2. изменить позицию объекта,

    3. нарисовать объект в текущей позиции.

    Действия 1 и 3 реализуются с помощью методов стереть и нарисовать, а действие 2 - с помощью присвоения нового значения. Теперь обратим внимание на то, что эта последовательность действий одинакова для всех объектов, наследующих свои свойства от объекта геометрическая фигура. Различие только в том, что методы стереть и нарисовать должны вызываться для того объекта, который вызвал метод переместить. Это вариант динамического полиморфизма, который в языках программирования реализуется с помощью виртуальных функций.

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

    Когда разрабатывается объектная программа, необходимо забыть о конкретной задаче и сконцентрироваться на объектах предметной области, то есть той области для которой создается программа. Пусть в качестве задачи формулируется создать графический редактор. При процедурном подходе проектируется набор подпрограмм, например ⌠Нарисовать точку■, ⌠Нарисовать прямоугольник■, ⌠Нарисовать окружность■, ⌠Переместить точку■, ⌠Удалить невидимые линии■, ⌠Вывести содержимое экрана на принтер■, ⌠Команда сохранить файл■ и т.п. Если создание объектной программы ведется по тем же принципам, то она будет гораздо хуже, чем обычная процедурная программа. За счет того, что сами по себе свойства объектов ( например, инкапсуляция ) не дают никаких преимуществ. Эти преимущества реализуются только при умелом определении объектов. Рассмотрим такой пример. Необходимо создать объект для представления хэш-таблицы, хранящей фамилии, имена студентов группы.

Вариант 1:

тип:

элемент хэш-таблицы

атрибуты:

фамилия : строка

имя : строка

отчество : строка

╧ группы : строка

объект:

хэш-таблица

атрибуты:

массив элементов типа элемент хэш-таблицы

количество элементов

методы:

вставить элемент( элемент : элемент хэш-таблицы )

удалить элемент ( фамилия : строка )

вычислить хэш-функцию( фамилия : строка )

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

Вариант 2:

объект:

элемент хэш-таблицы

атрибуты:

ключ : строка

объект:

хэш-таблица

атрибуты:

массив элементов типа элемент хэш-таблицы

количество элементов

методы:

вставить элемент( элемент : элемент хэш-таблицы )

удалить элемент ( фамилия : строка )

вычислить хэш-функцию( фамилия : строка )

объект:

элемент хэш-таблицы

атрибуты:

фамилия : строка

имя : строка

отчество : строка

╧ группы : строка

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

3.4 Объекты и экземпляры объектов

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

    а) объект не может иметь экземпляров (имеет 0 экземпляров)

    б) объект может иметь только один экземпляр в рамках данной задачи

    в) объект может иметь много экземпляров

    Примером отношений являются:

    а) объект млекопитающее не может иметь экземпляров, т.к. любое реальное млекопитающее является экземпляром объекта-потомка от млекопитающего.

    б) объект "президент России" может иметь только один экземпляр в течение некоторого периода времени.

    в) объект ястерб-тетеревятник имеет множество экземпляров.

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

3.5 Варианты наследования

    Использование наследования обычно вызвано необходимостью достичь одну из следующих целей:

  1. Построение принципиально нового объекта, базирующегося на свойствах существующего.
  2. Расширение и изменение функциональности имеющегося объекта.

    В первом случае, примером может являться построения объектов "Прямоугольник", "Ромб", "Эллипс", на основе объекта "Геометрическая фигура", а иллюстрацией для второго пункта является создание объекта "Прямоугольник с утолщенной линией", путем модификации объекта "Прямоугольник".

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

    Обычный вариант наследования в объектно-ориентированном подходе √ наследование типа "является". Типы объекта-наследника и объекта-родителя в этом случае имеют одну природу и являются сравнимыми. У объекта имеется один родитель.

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

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

Назад Оглавление Вперед