wiki:ru/signals

Version 1 (modified by vadim.godunko, 10 years ago) ( diff )

--

Механизм Signal-Slot

Приятная и полезная концепция, приходящая на замену классической концепции подпрограмм обратного вызова. Основные отличия:

  • сигналы и слоты есть части типа, наравне с полями записи и примитивными подпрограммами;
  • отсуствует понятие "данных пользователя", задаваемых при выполнении соединения;
  • неизвестен (теоретически) объект-отправитель;
  • может использоваться в для межзадачного взаимодействия в событийно управляемых программах.

Не все перечисленные выше требования легко решить средствами Ada.

Первый вариант

API библиотеки поддержки

Библиотека поддержки состоит из нескольких основных пользовательских пакетов. Корневой пакет определяет базовый тип, способный взаимодействовать с механизмом сигналов/слотов. Все пользовательские типы должны быть порождены от него.

package Objects is

   type Abstract_Object is
     abstract new Ada.Finalization.Limited_Controlled with private;

private
   ...
end Objects;

Дочерние пакеты предоставляют возможность создания сигналов с определённым набором параметров и типом параметров. Они выполнены в виде настраиваемых пакетов, за исключением одного, определяющего сигналы без параметров:

package Objects.Signals is

   ----------------------
   -- Signal_Connector --
   ----------------------

   type Signal_Connector (<>) is limited private;

   generic
      type T is abstract new Abstract_Object with private;

   package Generic_Connectors is

      procedure Connect
       (Self   : Signal_Connector;
        Object : not null access T'Class;
        Method : not null access procedure (Self : not null access T));

   end Generic_Connectors;

   ------------
   -- Signal --
   ------------

   type Signal
    (Object : not null access Abstract_Object'Class) is tagged limited private;

   not overriding procedure Emit (Self : Signal);

   not overriding function Connector
    (Self : in out Signal) return Signal_Connector;

private
   ...
end Objects.Signals;

Тип Signal_Connector предназначен для выполнения операций подключения/отключения соединений. Тип Signal предназначен для объявления поля записи, выполяющего обработку сигналов.

Настраиваемый пакет Generic_Connectors предназначен для настройки на конкретный тип подключаемого объекта и содержит подпрограммы управления соединениями.

Пример использования

В качестве примера определим два тэговых типа Emitter и Collector, первый будет возбуждать сигнал, а второй его получать.

Код спецификации и реализации первого приведён ниже.

with Objects.Signals;

package Emitters is

   type Emitter is new Objects.Abstract_Object with private;

   function Signal
    (Self : not null access Emitter) return Objects.Signals.Signal_Connector;

   procedure Test (Self : not null access Emitter);

private

   type Emitter is new Objects.Abstract_Object with record
      Signal : aliased Objects.Signals.Signal (Emitter'Access);
   end record;

end Emitters;
package body Emitters is

   ------------
   -- Signal --
   ------------

   function Signal
    (Self : not null access Emitter) return Objects.Signals.Signal_Connector is
   begin
      return Self.Signal.Connector;
   end Signal;

   ----------
   -- Test --
   ----------

   procedure Test (Self : not null access Emitter) is
   begin
      Self.Signal.Emit;
   end Test;

end Emitters;

Для типа объявлена подпрограмма Signal, возвращающая Signal_Connector и позволяющая выполнять операции подключения/отключения.

Подпрограмма Test предназначена для демонстрации работы механизма и просто выполняет возбуждение сигнала.

Тип Collector, предназначенный для обработки полученного сигнала выглядит следующим образом:

with Objects;

package Collectors is

   type Collector is new Objects.Abstract_Object with private;

   procedure Process (Self : not null access Collector);

private

   type Collector is new Objects.Abstract_Object with null record;

end Collectors;
with Ada.Text_IO;

package body Collectors is

   procedure Process (Self : not null access Collector) is
   begin
      Ada.Text_IO.Put_Line ("Processing");
   end Process;

end Collectors;

Для выполнения подключения необходимо так же выполнить настройку пакета Generic_Connectors:

with Objects.Signals;

package Collectors.Connections is
  new Objects.Signals.Generic_Connectors (Collector);

Главная подпрограмм выглядит следующим образом:

with Collectors.Connections;
with Emitters;

procedure Main is
   C : aliased Collectors.Collector;
   E : aliased Emitters.Emitter;

begin
   Collectors.Connections.Connect
    (E.Signal, C'Access, Collectors.Process'Access);
   E.Test;
end Main;

Выводы

Выглядит вполне приемлемо. Однако, слишком много необходимо сделать для выполнения подключения. Одна из возможных идей для рассмотрения - настройка специального пакета, принимающего тип и его подпрограмму, а уже потом использование подпрограммы Connect из него.

Note: See TracWiki for help on using the wiki.