Суть известного наблюдателя / наблюдаемого паттерна состоит в том, что у вас есть наблюдаемый объект, который производит события различного рода, и один или несколько объектов- наблюдателей, которые регистрируют себя как заинтересованные в уведомлении, когда происходят эти события.
Конечно, мы представляем каждый тип события как тип, обычно класс, хотя ничто не мешает нам использовать тип интерфейса в качестве типа события.
Например:
| 
 1 
2 
 | 
class Started() {}class Stopped() {} | 
Тип события может быть даже общим:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
17 
 | 
class Created<out Entity>        (shared Entity entity)         given Entity satisfies Object {    string => "Created[``entity``]";}class Updated<out Entity>        (shared Entity entity)         given Entity satisfies Object {    string => "Updated[``entity``]";}class Deleted<out Entity>        (shared Entity entity)         given Entity satisfies Object {    string => "Deleted[``entity``]";} | 
Конечно, у нас есть мощные механизмы для абстрагирования типов событий, например:
| 
 1 
2 
3 
4 
5 
 | 
alias Lifecycle<Entity>         given Entity satisfies Object        => Created<Entity> |           Updated<Entity> |           Deleted<Entity>; | 
Наблюдатель, как правило, по сути является не чем иным, как функцией, которая принимает определенный тип события в качестве параметра.
 Например, эта анонимная функция наблюдает за созданием User s: 
| 
 1 
2 
 | 
(Created<User> userCreated)         => print("new user created: " + userCreated.entity.name) | 
Эта анонимная функция наблюдает события жизненного цикла любого вида объекта:
| 
 1 
2 
 | 
(Lifecycle<Object> event)         => print("something happened: " + event) | 
Типы объединения и пересечения дают нам хороший способ выразить соединение и дизъюнкцию типов событий:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
 | 
void (Created<User>|Deleted<User> userEvent) {    switch (userEvent)    case (is Created<User>) {        print("user created: " + userEvent.entity.name);    }    case (is Deleted<User>) {        print("user deleted: " + userEvent.entity.name);    }} | 
  Теперь здесь мы можем сделать что-то действительно милое.  Как правило, в других языках наблюдаемый объект предоставляет различные операции регистрации наблюдателя, по одной для каждого типа события, которое производит объект.  Мы собираемся определить универсальный класс Observable который работает для любого типа события и использует усовершенствованные обобщенные типы для отображения событий в функции наблюдателя. 
| 
 1 
2 
3 
4 
 | 
shared class Observable<in Event>()         given Event satisfies Object {    ...} | 
  Параметр типа Event захватывает различные виды событий, которые создает этот объект, например, Observable<Lifecycle<User>> создает события типа Created<User> , Updated<User> и Deleted<User> . 
Нам нужен список для хранения наблюдателей в:
| 
 1 
 | 
value listeners = ArrayList<Anything(Nothing)>(); | 
  Здесь Anything(Nothing) является супертипом любой функции с одним параметром. 
  Метод addObserver() регистрирует функцию наблюдателя в Observable : 
| 
 1 
2 
3 
4 
 | 
shared void addObserver<ObservedEvent>        (void handle(ObservedEvent event))        given ObservedEvent satisfies Event        => listeners.add(handle); | 
  Этот метод принимает функции наблюдателя только для некоторого подмножества событий, фактически произведенных Observable .  Это ограничение обеспечивается верхней границей given ObservedEvent satisfies Event . 
  Метод raise() производит событие: 
| 
 1 
2 
3 
4 
 | 
shared void raise<RaisedEvent>(RaisedEvent event)        given RaisedEvent satisfies Event        => listeners.narrow<Anything(RaisedEvent)>()            .each((handle) => handle(event)); | 
  Опять же, верхняя граница обеспечивает, что этот метод принимает только те объекты событий, которые имеют тип события, созданный Observable . 
  Этот метод использует новый метод narrow() Iterable в Цейлоне 1.2, чтобы отфильтровать функции-наблюдатели, которые не принимают возбужденный тип события.  Этот метод реализован с использованием усовершенствованных обобщений.  Вот его определение в Iterable<Element> : 
| 
 1 
2 
 | 
shared default {Element&Type*} narrow<Type>()         => { for (elem in this) if (is Type elem) elem }; | 
  То есть, если у нас есть поток Element s, и мы вызываем narrow<Type>() , явно передавая произвольный тип Type , то мы возвращаем поток всех элементов исходного потока, которые являются экземплярами Type .  Это, естественно, поток Element&Type s. 
  Теперь, наконец, если мы определим экземпляр Observable : 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
 | 
object userPersistence         extends Observable<Lifecycle<User>>() {    shared void create(User user) {        ...        //raise an event        raise(Created(user));    }    ...} | 
Затем мы можем зарегистрировать наблюдателей для этого объекта следующим образом:
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
16 
 | 
//observe User creation eventsuserPersistence.addObserver(        (Created<User> userCreated)         => print("new user created: " + userCreated.entity.name));//observe User creation and deletion eventsuserPersistence.addObserver(        void (Created<User>|Deleted<User> userEvent) {    switch (userEvent)    case (is Created<User>) {        print("user created: " + userEvent.entity.name);    }    case (is Deleted<User>) {        print("user deleted: " + userEvent.entity.name);    }}); | 
Обратите внимание, что с типами объединения и пересечения, подтипами и дисперсией мы находимся с мощным языком выражений, позволяющим точно определить, какие именно типы событий нас интересуют, с учетом безопасности типов, прямо в списке параметров функции наблюдателя.
  Для записи вот полный код Observable : 
| 
 01 
02 
03 
04 
05 
06 
07 
08 
09 
10 
11 
12 
13 
14 
15 
 | 
shared class Observable<in Event>()         given Event satisfies Object {    value listeners = ArrayList<Anything(Nothing)>();    shared void addObserver<ObservedEvent>            (void handle(ObservedEvent event))            given ObservedEvent satisfies Event            => listeners.add(handle);    shared void raise<RaisedEvent>(RaisedEvent event)            given RaisedEvent satisfies Event            => listeners.narrow<Anything(RaisedEvent)>()                .each((handle) => handle(event));} | 
  Наконец, предостережение: точный код, приведенный выше, не компилируется в Ceylon 1.1, потому что метод narrow() является новым и из-за исправленной ошибки в проверке типов.  Но это будет работать в предстоящем выпуске Цейлона 1.2. 
| Ссылка: | Уникальный подход к наблюдателю / наблюдаемой модели на Цейлоне от нашего партнера JCG Гэвина Кинга в блоге команды Ceylon Team . |