Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
OOP / books / Osnovi objektno-orientirovannogo programmirovaniya.pdf
Скачиваний:
62
Добавлен:
03.03.2016
Размер:
9.04 Mб
Скачать

Рис. 15.4. Структура множественного и единичного наследования

Окна - это деревья и прямоугольники

Рассмотрим оконную систему с произвольной глубиной вложения окон:

Рис. 15.5. Окна и подокна

В соответствующем классе WINDOW мы найдем компоненты двух основных видов:

*те, что рассматривают окно как иерархическую структуру (список подокон, родительское окно, число подокон, добавить, удалить подокно);

*те, что рассматривают окно как графический объект (высота, ширина, отобразить, спрятать, переместить окно).

Этот класс можно написать как единое целое, смешав все компоненты. Однако такой проект будет не самым удачным. Класс WINDOW следует рассматривать как сочетание двух

абстракций:

*иерархической структуры, представленной классом TREE ;

*прямоугольного экранного объекта, представленного классом RECTANGLE. На практике класс будет описан так:

class WINDOW inherit TREE [WINDOW] RECTANGLE

feature

... Характерные компоненты окна ...

end

Обратите внимание, класс TREE является родовым (generic) классом, а потому требует указания фактического родового параметра, здесь - самого класса WINDOW. Рекурсивная природа определения отражает рекурсию, присущую моделируемой ситуации, - окно является одновременно деревом окон.

Далее, можно подметить, что отдельные окна не содержат ничего, кроме текста. Эту особенность окон можно реализовать вложением, представив класс TEXT_WINDOW как клиента класса STRING, введя атрибут

text: STRING

Предпочтем, однако, вариант, в котором текстовое окно является одновременно строкой. В этом случае используем множественное наследование с родителями WINDOW и STRING. (Если же все наши окна содержат лишь текст, их можно сделать прямыми потомками TREE, RECTANGLE и STRING, однако и здесь решение "в два хода" возможно будет более предпочтительным.)

Деревья - это списки и их элементы

Класс дерева TREE - еще один яркий пример множественного наследования.

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

Мы же заметим, что между понятиями дерева и узла нет серьезных различий. Узел можно определить как поддерево, корнем которого он является. В итоге приходим к классу TREE [G], который описывает как узлы, так и деревья. Формальный родовой параметр G отражает тип данных в каждом узле. Следующее дерево, является, например, экземпляром TREE [INTEGER]:

Рис. 15.6. Дерево целых чисел

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

Рис. 15.7. Представление списка Эти понятия позволяют прийти к простому определению дерева: дерево (или его узел) есть

список, - список его потомков, но является также потенциальным элементом списка, поскольку может представлять поддерево другого дерева.

Определение: дерево

Дерево - это список и элемент списка одновременно.

Это определение еще потребует доработки, однако, уже сейчас позволяет описать класс:

deferred class TREE [G] inherit LIST [G]

CELL [G] feature

...

end

От класса LIST наследуются такие компоненты как количество узлов ( count ), добавление, удаление узлов и т. д.

От класса CELL наследуются компоненты, позволяющие работать с узлами, задающими родителя или братьев: следующий брат, добавить брата, присоединить к другому родителю.

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

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

|Этот процесс подобен процессу, применяемому математиками при комбинировании

теорий: топологическое векторное пространство является одновременно топологическим пространством и векторным пространством. Здесь тоже необходимы некоторые связующие аксиомы. |

Составные фигуры

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

Рассмотрим структуру, введенную в предыдущей лекции для изучения наследования и содержащую классы графических фигур: FIGURE, OPEN_FIGURE, POLYGON, RECTANGLE,

ELLIPSE и т.д. До сих пор в этой структуре использовалось лишь единичное наследование.

Рис. 15.8. Элементарные фигуры Пусть в этой иерархии представлены все нужные нам базовые фигуры. Однако в библиотеку

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

Рис. 15.9. Составная фигура Колесо, в свою очередь, может пригодиться при рисовании велосипеда, и т. д.

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

Назовем новые фигуры составными ( COMPOSITE_FIGURE ). Каждую такую фигуру, безусловно, надо порождать от FIGURE, что позволит ей быть "на равных" с базовыми примитивами. Составная фигура - это еще и список фигур, ее образующих, каждая из которых может быть базовой или составной. Воспользуемся множественным наследованием (рис. 15.10).

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

class COMPOSITE_FIGURE inherit FIGURE

LINKED_LIST [FIGURE] feature

...

end

Рис. 15.10. Составная фигура - это фигура и список фигур одновременно

Предложение feature записывать приятно вдвойне. Работа с составными фигурами во многом сводится к работе со всеми их составляющими. Например, процедура display может быть реализована так:

display is

-- Отображает фигуру, последовательно отображая все ее компоненты. do

from start until

Соседние файлы в папке books