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


Универсальность


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

generic type G is private; package STACKS is ... Все, как и ранее, заменяя все вхождения FLOAT на G ... end STACKS;

Предложение generic синтаксически более тяжелое, чем наша ОО-нотация для универсальных классов (class C [G]...), но зато в нем больше возможностей. В частности, параметры, объявляемые в generic, могут представлять не только типы, но и подпрограммы. В приложении B эти возможности обсуждаются при сравнении универсальности и наследования.

В теле пакета generic не повторяется, там достаточно конкретный тип FLOAT заменить родовым G.

Спецификация is private заставляет остальную часть пакета рассматривать G как закрытый тип. Это означает, что сущности этого типа могут использоваться только в операциях, применимых ко всем типам языка Ada: в качестве исходного или целевого объекта при присваивании, как операнд в проверке равенства, как фактический аргумент в подпрограмме, и в некоторых других специальных операциях. Это близко к соглашению для неограниченных формальных параметров универсальных классов нашей нотации. В языке Ada доступны и другие возможности. Можно ограничить операции, объявляя параметр как limited private, что запрещает все использования кроме фактических аргументов подпрограмм.

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

package REAL_STACKS_1 is new STACKS (FLOAT);

Родовое порождение - главный механизм языка Ada адаптации модулей. Из-за отсутствия наследования он менее гибок, поскольку можно выбирать только между универсальными модулями (параметризованными, но не используемыми непосредственно) или используемыми модулями (более не расширяемыми). Напротив, наследование допускает произвольные расширения существующих модулей, в соответствии с принципом Открыт-Закрыт. В приложении даются подробности сравнения.



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