Программирование путем расширения подразумевает, что при необходимости добавления в программную систему каких-либо новых свойств она может быть выполнена простым добавлением нового кода, без необходимости внесения изменений в уже существующие модули программного обеспечения.
При этом, поддержка обеспечиваемая со стороны языка программирования является очень полезной.
Представим себе функцию, которая читает до 20 сообщений с какого-либо интерфейса, обрабатывает статистику и генерирует какой-либо итоговый результат.
Для остальной части системы непосредственно необходим только итоговый результат, и ее не заботят входные сообщения или работа интерфейса.
В таком случае, простым решением будет помещение в самостоятельный пакет функции Summarizer, вычисляющей итоговый результат, вместе с перечислением переменных, которые указывают этой функции на то, какой интерфейс необходимо использовать:
| package Simple_Approach is
type Interfaces is (Disk_File, Serial_Interface, ...); type Summary_Type is record . . . end record; function Summarizer (Interface_To_Use: Interfaces) return Summary_Type; end Simple_Approach; |
Естественно, что в результате такого простого решения, при необходимоти добавить какой-либо новый интерфейс потребуется переписать заново тип Interfaces
и функцию Summarizer, после чего, перекомпилировать все модули которые указывают пакет Simple_Approach в спецификаторе withs.
Необходимо заметить, что Ада очень часто используется в жизненно-критических системах (например, в авиационном оборудовании), где каждый программный модуль должен пройти длительный и дорогостоящий цикл тестирования скомпилированного объектного кода.
Следовательно, после перекомпиляции модуля этот цикл тестирования должен быть пройден заново даже в случае отсутствия изменений в исходном тексте.
Программирование путем расширения позволяет избавиться от подобных переписываний и перекомпиляций.
Первым вопросом, в этом случае, является: "что необходимо расширять?".
|
with Message; package Generic_Interface is type Flag is tagged null record; procedure Get (Which_Interface: Flag; Data: Message.Data_Type); end Generic_Interface; |
|
with Generic_Interface; package Extension_Approach is function Summarizer (Interface_To_Use: Generic_Interface.Flag'Class) return Summary_Type; end Extension_Approach; - - - - - - with Messages; package body Extension_Approach is function Summarizer (Interface_To_Use: Generic_Interface.Flag'Class) return Summary_Type is Data: array (1..20) of Message.Data_Type; begin for I in 1 .. 20 loop Get (Interface_To_Use, Data (I)); exit when Data (I).Last_Message; end loop; ... |
|
with Message; with Generic_Interface; package Disk_Interface is type Flag is new Generic_Interface.Flag with null record; procedure Get (Which_Interface: Flag; Data: Message.Data_Type); end Disk_Interface; |
|
Summary := Extension_Approach.Summarizer (Disk_Interface.Flag'(null record)); |
|
type Interface_Selector is access constant Flag'Class; end Generic_Interface; |
|
Selected: constant Flag := Flag'(null record); Selection: constant Generic_Interface.Interface_Selector := Selected'Access; end Disk_Interface; |
|
with Disk_Interface; with Extension_Approach; use Extension_Approach; procedure User is Sum: Summary_Type; begin Sum := Summarizer (Disk_Interface.Selected); |
|
package Interfaces is Current: Generic_Interface.Interface_Selector; end Interfaces; - - - - - with Interfaces; with Extension_Approach; use Extension_Approach; procedure User is Sum: Summary_Type; begin Sum := Summarizer (Interfaces.Current); . . . |
|
with Message; package Generic_Interface is type Flag is tagged null record; procedure Get (Which_Interface: Flag; Data: Message.Data_Type); procedure Start (Which_Interface: Flag); -- ничего не выполняет procedure Stop (Which_Interface: Flag); -- ничего не выполняет . . . - - - - - - with Message; package Disk_Interface is type Flag is new Generic_Interface.Flag with null record; procedure Get (Which_Interface: Flag; Data: Message.Data_Type); -- нам нет нужды запускать или останавливать диск, таким образом, Start -- ничего не наследует от Generic_Interface . . . - - - - - - with Message; package Serial_Interface is type Flag is new Generic_Interface.Flag with null record; procedure Get (Which_Interface: Flag; Data: Message.Data_Type); -- запуск и остановка последовательного интерфейса procedure Start (Which_Interface: Flag); procedure Stop (Which_Interface: Flag); . . . |
|
with Interfaces; with Extension_Approach; use Extension_Approach; procedure User is Sum: Summary_Type; begin Start (Interfaces.Current); Sum := Summarizer (Interfaces.Current); Stop (Interfaces.Current); . . . |
| Copyright (C) А.Гавва | V-0.4w май 2004 |