Основы объектно-ориентированного программирования
Шрифт:
[x]. Предусловие задает область определения DOM функции r (подмножество I, на котором r гарантированно вырабатывает результат).
[x]. Постусловие задает для каждого x из DOM подмножество RESULTS(x) множества O, такое, что r (x) RESULTS (x). Так как постусловие не всегда однозначно описывает результат, это подмножество может иметь больше одного элемента.
Правило Утверждения Переобъявления означает, что повторное объявление может расширять область определения и сужать множество результатов. Пометив новые множества знаком ', запишем требования, закрепленные этим правилом:
Предусловие устанавливает, что подпрограмма и ее повторные объявления, как минимум, должны принимать некоторые входы (DOM), хотя повторные объявления могут это множество и расширить. Постусловие говорит, что результаты, возвращаемые подпрограммой и ее повторными объявлениями, могут, самое большее, содержать значения из RESULTS(x), однако, постусловия при повторных объявлениях могут это множество сузить.
В этом описании состояние системы в период выполнения определяется состоянием (значениями) всех достижимых объектов. Кроме того, входные состояния (элементы I) также включают в себя значения аргументов. Более подробное введение в математическое описание программ и языков программирования см. в [M 1990].
Глобальная структура наследования
Ранее мы уже ссылались на универсальные (universal) классы GENERAL и ANY, а также на безобъектный (objectless) класс NONE. Пришло время пояснить их роль и представить глобальную структуру наследования.
Универсальные классы
Удобно использовать следующее соглашение:
Правило Универсального Класса
Любой класс, не содержащий предложение наследования, неявно содержит предложение вида:
inherit ANY,
ссылающееся на класс ANY из библиотеки Kernel.
Тем самым становится возможным определить по умолчанию целый ряд компонентов, наследуемых всеми классами. Эти компоненты реализуют общие, универсальные операции: копирование, клонирование, сравнение, базовый ввод и вывод.
Для большей гибкости поместим эти компоненты в класс GENERAL, чьим потомком является ANY. Сам класс ANY по умолчанию не имеет никаких компонентов, будучи классом вида: class ANY inherit GENERAL end. При создании нового проекта его менеджер может решить, какие общие для проекта компоненты следует включить в класс ANY, в то время как GENERAL остается всегда неизменным.
| Для построения нетривиального ANY можно прибегнуть к наследованию. В самом деле, класс ANY можно породить от некоторого HOUSE_STYLE или нескольких таких классов, не вводя циклы в иерархию наследования и не нарушая правило об универсальном классе: достаточно сделать класс HOUSE_STYLE и другие классы потомками GENERAL. Вынесенный на рис. 16.4 текст "Классы разработчика" означает все классы, написанные разработчиком и не порожденные от GENERAL явным образом. |
Рис. 16.4. Глобальная структура наследования
Нижняя часть иерархии
На рис. 16.4 представлен также класс NONE, антипод класса ANY, потомок всех классов, не имеющих собственных наследников и превращающий глобальную иерархию наследования классов в решетку (математическую структуру). NONE не имеет потомков, его нельзя переопределить - это лишь удобная фикция, однако, теоретическое существование такого класса оправдано и служит двум практическим целям:
[x]. Void– пустая ссылка, используемая наряду с другими ссылками, по соглашению имеет тип NONE. (Фактически, Void– это один из компонентов класса GENERAL.)
[x]. Чтобы скрыть компонент от всех клиентов, достаточно экспортировать его только классу NONE. Предложение feature {NONE}(практически эквивалентное feature {}, но записанное явно) или предложение наследования export {NONE}(на практике дающее тот же результат, что и export {}), делает компонент недоступным для любого класса, написанного разработчиком, ибо NONE не имеет потомков. Обратите внимание на то, что NONE скрывает и все свои компоненты.
Первое свойство объясняет, почему значение Void можно присвоить любому элементу ссылочного типа данных. До сих пор статус Void оставался некой загадкой, теперь, когда Void связано с классом NONE, этот статус становится очевидным, официальным и согласующимся с системой типов: по построению NONE является потомком всех классов, а потому мы можем использовать Void как допустимое значение любой ссылки, не нарушая правил описания типов.
По симметрии ко второму свойству заметим, что объявление, начинающееся с feature и экспортирующее все компоненты во все классы, написанные разработчиком, считается сокращением от feature {ANY}. Для повторного экспорта во все классы компонента родителя, доступ к которому был ограничен, можно использовать предложение export {ANY} или его не столь очевидное сокращение export.
Классы ANY и NONE обеспечивают замкнутость системы типов и полноту структуры наследования: решетка (это строго определенный математический термин) имеет свой верхний и нижний элемент.
Универсальные компоненты
Вот лишь некоторые компоненты, содержащиеся в классе GENERAL, а значит, доступные всем другим классам. Часть из них была введена и использована в предшествующих лекциях курса:
[x]. clone для создания клона (дубля) объекта, а также его "глубинный" вариант deep_clone для рекурсивного дублирования полной структуры объекта;
[x]. copy для копирования содержимого одного объекта в другой;
[x]. equal для сравнения объектов (поле-с-полем), а также его "глубинный" вариант deep_equal;
[x]. print и print_line– печать простого представления по умолчанию любого объекта (default representation);
[x]. tagged_out– строка, содержащая представление по умолчанию любого объекта, в котором каждое поле сопровождается своей меткой (tag) (соответствующим именем атрибута);