Предположим, что мы хотим создать пакет стека, но при этом, мы не хотим переписывать все подпрограммы. Мы уже имеем реализацию связанного списка, которая может служить основой для организации стека. Заметим, что пакет Lists сохраняет значения типа Integer.
Допустим, что существует пакет Lists, который описан следующим образом:
| package Lists is
type List is private; Underflow : exception; procedure Insert_At_Head(Item : in out List; Value : in Integer); procedure Remove_From_Head(Item : in out List; Value : out Integer); procedure Insert_At_Tail(Item : in out List; Value : in Integer); procedure Remove_From_Tail(Item : in out List; Value : out Integer); function Full(Item : List) return Boolean; function Empty(Item : List) return Boolean; -- возвращает пустой проинициализированный список function Init return List; private . . . end Lists; |
Позже можно будет использовать возможность Ады, которая позволяет скрыть полное описание типа в приватной секции.
В данном случае, описывается абсолютно новый тип (поскольку в этом заинтересован клиент), который реально реализован как производный тип.
В результате, клиент не может это "увидеть", и детали реализации остаются надежно спрятанными "под капотом".
Таким образом, реализация стека осуществляется следующим образом:
| with Lists;
package Stacks is type Stack is private; Underflow : exception; procedure Push(Item : in out Stack; Value : in Integer); procedure Pop(Item : in out Stack; Value : out Integer); function Full(Item : Stack) return Boolean; function Empty(Item : Stack) return Boolean; -- возвращает пустой проинициализированный стек function Init return Stack; private -- создаем новый тип, производя его от уже существующего -- это остается спрятанным от клиента, который будет -- использовать наш новый тип type Stack is new Lists.List; -- тип Stack наследует все операции типа List -- это неявно описывается как -- -- procedure Insert_At_Head(Item : in out Stack; Value : in Integer); -- procedure Remove_From_Head(Item : in out Stack; -- Value : out Integer); -- . . . -- function Full(Item : Stack) return Boolean; -- function Empty(Item : Stack) return Boolean; -- function Init return Stack; end Stacks; |
|
package body Stacks is procedure Push(Item : in out Stack; Value : in Integer) is begin Insert_At_Head(Item, Value); end Push; -- эту процедуру можно сделать более эффективной, используя: pragma Inline(Push); procedure Pop(Item : in out Stack; Value : out Integer) is begin Remove_From_Head(Item, Value); exception => when Lists.Underflow => raise Stacks.Underflow; end Pop; . . . end Stacks; |
|
function Full(Item : Stack) return Boolean; |
|
package body Stacks is function Full(Item : Stack) return Boolean is begin -- вызов оригинальной функции Full из другого пакета return Lists.Full(Lists.List(Item)); -- конверсия типа параметра end Full; . . . end Stacks; |
|
use Lists; package body Stacks is procedure Push(Item : in out Stack; Value : in Integer) is begin Insert_At_Head(Item, Value); end Push; procedure Pop(Item : in out Stack; Value : out Integer) is begin Remove_From_Head(Item, Value); exception => when Lists.Underflow => raise Stacks.Underflow; end Pop; -- примечательно, что исключение объявленное в другом пакете -- "транслируется" в исключение описанное внутри этого пакета function Full(Item : Stack) return Boolean is begin return Lists.Full(List(Item)); end Full; function Empty(Item : Stack) return Boolean is begin return Lists.Empty(List(Item)); end Empty; -- возвращает пустой проинициализированный стек function Init return Stack is begin return Stack(Lists.Init); end Init; end Stacks; |