std.signals

Переместиться к: Signal

Сигналы и Слоты — это реализация Шаблона проектирования «Наблюдатель». По существу, когда испускается Сигнал, по списку вызываются подключенные Наблюдатели (через вызов слота).
В D имеется несколько реализаций Сигналов и Слотов. Эта версия использует несколько новых возможностей в D, которые делают её использование проще и менее склонным к ошибкам. В частности, больше нет необходимости реализовывать слоты.

Ссылки: A Deeper Look at Signals and Slots
Наблюдатель (шаблон проектирования)
Wikipedia
Boost Signals (Статья на русском)
Qt

Об этом имеется множество дискуссий в группах новостей D, и несколько реализаций:
signal slots library
Signals and Slots in D
Dynamic binding -- Qt's Signals and Slots vs Objective-C
Dissecting the SS
about harmonia
Another event handling module
Suggestion: signal/slot mechanism
Signals and slots?
Signals and slots ready for evaluation
Signals & Slots for Walter
Signal/Slot mechanism?
Modern Features?
Delegates vs interfaces
The importance of component programming (properties, signals and slots, etc)
signals and slots

Недостатки:
Слоты могут быть только делегатами, сформированными из объектов класса или интерфейсами к объектам класса. Если для метода connect() (подсоединение) передается делегат к чему-то другому, например, методу структуры, вложенной функции или COM-интерфейсу, это приведёт к неопределённому поведению.
Не безопасно для нескольких потоков, работающих на одних и тех же сигналах или слотах.
Лицензия:
Boost License 1.0.
Авторы:
Walter Bright

Исходный код: std/signals.d

Переместиться к: connect · disconnect · emit · slot_t

template Signal(T1...)
Примешивается (mixin) для создания сигнала в пределах объекта класса.
Различные сигналы можно добавлять к классу именованием mixin'ов.
Примеры:
import std.signals;

int observedMessageCounter = 0;

class Observer
{   // наш слот
    void watch(string msg, int value)
    {
        switch (observedMessageCounter++)
        {
            case 0:
                assert(msg == "установка нового значения");
                assert(value == 4);
                break;
            case 1:
                assert(msg == "установка нового значения");
                assert(value == 6);
                break;
            default:
                assert(0, "Неизвестное наблюдение");
        }
    }
}

class Observer2
{   // наш слот
    void watch(string msg, int value)
    {
    }
}

class Foo
{
    int value() { return _value; }

    int value(int v)
    {
        if (v != _value)
        {   _value = v;
            // вызов всех подключенных слотов с двумя параметрами
            emit("установка нового значения", v);
        }
        return v;
    }

    // Примешиванием к коду нам нужно преобразовать Foo в сигнал
    mixin Signal!(string, int);

  private :
    int _value;
}

Foo a = new Foo;
Observer o = new Observer;
auto o2 = new Observer2;
auto o3 = new Observer2;
auto o4 = new Observer2;
auto o5 = new Observer2;

a.value = 3;                // не должно вызываться o.watch()
a.connect(&o.watch);        // o.watch - это слот
a.connect(&o2.watch);
a.connect(&o3.watch);
a.connect(&o4.watch);
a.connect(&o5.watch);
a.value = 4;                // должно вызваться o.watch()
a.disconnect(&o.watch);     // o.watch - это больше не слот
a.disconnect(&o3.watch);
a.disconnect(&o5.watch);
a.disconnect(&o4.watch);
a.disconnect(&o2.watch);
a.value = 5;                // не должно вызываться o.watch()
a.connect(&o2.watch);
a.connect(&o.watch);        // снова соединение
a.value = 6;                // должно вызваться o.watch()
destroy(o);                 // разрушение o должно автоматически отсоединить его
a.value = 7;                // не должно вызываться o.watch()

assert(observedMessageCounter == 2);
alias slot_t = void delegate(T1);
Слот реализуется как делегат. slot_t — тип делегата. Делегат должен быть экземпляром класса или интерфейсом к экземпляру класса. Члены экземпляров структур или вложенных функций нельзя использовать как слоты.
final void emit(T1 i);
Вызывает каждый из подсоединённых слотов, передавая им аргумент (-ы) i.
final void connect(slot_t slot);
Добавляет к списку слотов slot, который будет вызываться при вызове emit().
final void disconnect(slot_t slot);
Удаляет slot из списка слотов, вызываемых при вызове emit().