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

Ограниченная универсальность: подпрограммы


Мы можем написать подпрограмму, такую как minimum, указав тип COMPARABLE для ее аргументов. Основываясь на образце Ada, функция была бы объявлена следующим образом:

minimum (one: COMPARABLE; other: like one): like one is -- Минимальное из one и other do ... end

При ОО-разработке каждая подпрограмма появляется в классе и связывается с текущим экземпляром класса. Включив minimum в класс COMPARABLE, аргумент one станет неявным текущим экземпляром. Класс будет выглядеть так:

deferred class COMPARABLE feature infix "<=" (other: like Current): BOOLEAN is -- Текущий объект меньше или равен other? deferred end minimum (other: like Current): like Current is -- Минимальное из двух значений: текущего -- и other do if Current <= other then Result := Current else Result := other end end end

Для вычисления минимума двух элементов необходимо объявить их тип как эффективного потомка COMPARABLE, с заданной реализацией операции сравнения <=, например:

class INTEGER_COMPARABLE inherit COMPARABLE creation put feature -- Initialization put (v: INTEGER) is -- Инициализация значением v. do item := new end feature -- Access item: INTEGER; -- Значение, связанное с текущим объектом feature -- Basic operations infix "<=" (other: like Current): BOOLEAN is -- Текущий объект меньше или равен other? do Result := (item <= other.item) end; end

Для нахождения минимума двух целых теперь можно применять функцию minimum к сущностям ic1 и ic2, чьи типы не INTEGER, а INTEGER_COMPARABLE:

ic3 := ic1.minimum (ic2)

Для использования родовых функций infix <= и minimum придется исключить прямые ссылки на целые, заменив их сущностями INTEGER_COMPARABLE, поскольку этого требует атрибут item и подпрограмма put. Более того, придется вводить подобных потомков COMPARABLE, таких как STRING_COMPARABLE и REAL_COMPARABLE, для каждого типа, требующего своей версии minimum.

Заметьте, механизм закрепленных объявлений является основой обеспечения корректности. Если бы аргумент minimum в COMPARABLE был бы объявлен как COMPARABLE, а не like Current, то следующий вызов был бы синтаксически допустим:


ic1.minimum (c)если c принадлежал бы типу COMPARABLE, но не был бы типом INTEGER_COMPARABLE. Понятно, что такой вызов мог быть некорректным. Все это применимо и к RING_ELEMENT.

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

Эмуляция ограниченной универсальности (1)

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


Содержание раздела