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

         

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


Предыдущая дискуссия переносится и на пакеты. Для эмуляции абстракции матриц, которую Ada реализует пакетом MATRICES, можно использовать класс:

class MATRIX feature anchor: RING_ELEMENT is do end implementation: ARRAY2 [like anchor] item (i, j: INTEGER): like anchor is -- Значение элемента с индексами (i, j) do Result := implementation.item (i, j) end put (i, j: INTEGER; v: like anchor) is -- Присвоить значение v элементу с индексами (i, j) do implementation.put (i, j, v) end infix "+" (other: like Current): like Current is -- Матричная сумма текущей матрицы matrix и other local i, j: INTEGER do create Result.make (...) from i := ... until ... loop from j := ... until ... loop Result.put ((item (i, j) + other.item (i, j)), i, j) j := j + 1 end i := i + 1 end end infix "*"(other: like Current): like Current is -- Матричное произведение текущей матрицы и other local ... do ... end end

С типом аргумента put и результата item связана интересная проблема: он должен быть RING_ELEMENT, но соответствующим образом переопределен в классах-потомках. Закрепленное объявление дает решение проблемы, но здесь, на первый взгляд, нет атрибута, который мог бы послужить якорем. Это не должно нас останавливать: следует объявить искусственный якорь, называемый anchor. Его единственное предназначение - быть переопределенным в подходящий тип потомка RING_ELEMENT будущими потомками MATRIX (например, BOOLEAN_RING в BOOLEAN_MATRIX и т. д.). Во избежание потерь памяти в экземплярах anchor объявляется как функция, а не как атрибут. Техника искусственного якоря полезна для сохранения согласованности типов, когда, как в данном случае, нет естественного якоря среди атрибутов класса.

Некоторые детали цикла, также как и тело инфиксной операции *, остались вне рассмотрения, но дополнить их просто. Компоненты put и item, применяемые в реализации, пришли из библиотечного класса ARRAY2, описывающего двумерные массивы.

Для определения эквивалента родового пакета Ada, показанного ранее:


package BOOLEAN_MATRICES is new MATRICES (BOOLEAN, false, true, "or", "and");следует прежде всего объявить соответствующее булево кольцо:

class BOOLEAN_RING_ELEMENT inherit RING_ELEMENT redefine zero, unity end creation put feature -- Initialization put (v: BOOLEAN) is -- Инициализация значением v do item := v end feature -- Access item: BOOLEAN feature -- Basic operations infix "+" (other: like Current): like Current is -- Булево сложение: or do create Result.put (item or other.item) end infix "*"(other: like Current): like Current is -- Булево умножение: and do create Result.put (item and other.item) end zero: like Current is -- Нулевой элемент булева кольца для сложения once create Result.put (False) end unity: like Current is -- Нулевой элемент для булева умножения once create Result.put (True) end endЗаметьте, ноль и единица реализуются однократными функциями.

Тогда для получения родового порождения пакета Ada следует просто определить наследника BOOLEAN_MATRIX от MATRIX, где нужно только переопределить anchor - искусственный якорь; все остальные типы будут следовать автоматически:

class BOOLEAN_MATRIX inherit MATRIX redefine anchor end feature anchor: BOOLEAN_RING_ELEMENT endЭта конструкция достигает эффекта ограниченной универсальности благодаря использованию наследования, подтверждая для пакетов результаты эмуляции, проиллюстрированные ранее для подпрограмм.


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