Организация взаимодействий по подписке

Существует масса ситуаций, когда прямой «цепочечный» стиль организации взаимодействий посредством функции dojo.connect является именно тем средством, которое необходимо для решения проблем. Однако существует не меньше ситуаций, когда требуется более опосредованный «широковещательный» стиль организации взаимодействий, когда различные виджеты взаимодействуют друг с другом анонимно.
В таких случаях можно использовать функции dojo.publish и dojo.sub-scribe.

Классическим примером является ситуация, когда необходимо организовать взаимодействие между одним объектом JavaScript и несколькими другими объектами по типу отношений «один ко многим». Вместо того чтобы создавать и управлять множественными соединениями, создаваемыми с помощью функции dojo.connect, которые больше напоминают одно связное действие, значительно проще организовать передачу уведомления о событии, произошедшем в одном виджете (наряду с данными, сопутствующими этому событию) , чтобы другие виджеты могли подписаться на получение этих извещений и автоматически принимать соответствующие меры. Вся прелесть такого подхода состоит в том, что объект, осуществляющий отправку уведомлений, ничего не должен знать о других объектах и даже не должен делать никаких предположений об их существовании.


Другим классическим примером такого рода взаимодействий являются портлеты – подключаемые компоненты интерфейса (http://en.wikipedia.org/wiki/Portlet1), которые обслуживаются вебпорталом, иногда через панель управления.

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

Для начала, чтобы определить, какой стиль организации взаимодействий лучше подходит для решения проблемы, попробуйте ответить на следующие вопросы:
• Предполагаете ли вы (и насколько это правильно) публиковать прикладной интерфейс виджета, который вы разрабатываете? Если нет, тогда вам определенно следует использовать взаимодействия по подписке, потому что это позволит вам свободно менять архитектуру виджета, не опасаясь вступить в конфликт с его опубликованным API.
• Предполагается ли одновременное использование нескольких однотипных виджетов, которые порождают один и тот же тип событий?

Если да, тогда вам определенно следует использовать взаимодействия, основанные на прямых соединениях, потому что в противном случае вам придется разрабатывать дополнительную логику, которая будет определять, какой виджет и на какое событие должен реагировать.
• Разрабатываете ли вы виджет, содержащий другие виджеты в отношении «имеет»? Если да, тогда вам следует использовать взаимодействия, основанные на прямых соединениях.
• Предполагается ли возможность организации взаимодействий по принципу «один ко многим» или «многие ко многим»? Если да, то гда определенно следует использовать взаимодействия по подписке, чтобы минимизировать тяжесть организации взаимодействий, основанных на прямых соединениях.
• Предполагается ли, что взаимодействия должны быть полностью анонимными и должна ли быть обеспечена свобода в выборе взаимодействующих сторон? Если да, тогда следует использовать взаимодействия по подписке.

Не будем долго задерживаться и рассмотрим интерфейс организации взаимодействий по подписке.


Обратите внимание, что в случае функции dojo.subscribe можно опустить параметр context, а функция выполнит необходимую нормализацию аргументов (точно так же, как и в случае с функцией dojo.connect):
dojo.publish(/*String*/topic, /*Array*/args)
dojo.subscribe(/*String*/topic, /*Object|null*/context,
/*String|Function*/method) //Возвращает Handle
dojo.unsubscribe(/*Handle*/handle)

Давайте рассмотрим простой пример, основанный на использовании функций dojo.subscribe и dojo.publish:
function Foo(topic) {
this.topic = topic;
this.greet = function() {
console.log("Hi, I'm Foo");
/* Объект Foo публикует информацию, но не для конкретного получателя */
dojo.publish(this.topic);
}
}
function Bar(topic) {
this.topic = topic;
this.greet = function() {
console.log("Hi, I'm Bar");
}
/ * Объект Bar подписывается на информацию, но не от конкретного источника */
dojo.subscribe(this.topic, this, "greet");
}
var foo = new Foo("/dtdg/salutation");
var bar = new Bar("/dtdg/salutation");
foo.greet(); //Hi, I'm Foo...Hi, I'm Bar

Как видите, функция connect связывает конкретный источник с конкретным адресатом, а функции publish/subscribe позволяют работать с широковещательными посылками, которые могут исходить из любого источника и обрабатываться любыми получателями, заинтересованными в получении таких посылок.


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

Давайте посмотрим, как можно отписаться от получения уведомлений, внеся изменения в реализацию объекта Bar. Пусть теперь объект Bar отвечает на сообщение, публикуемое объектом Foo, только один раз:
function Bar(topic) {
this.topic = topic;
this.greet = function() {
console.log("Hi, I'm bar");
dojo.unsubscribe(this.handle);
//не тревожь ты меня, я тебе не отвечу
}
this.handle = dojo.subscribe(this.topic, this, "greet");
}

Обратите внимание, что существует возможность вместе с сообщением передать как второй аргумент функции publish массив значений в виде именованных параметров, которые будут переданы обработчику, подписанному с помощью функции subscribe.
И, в заключение, предположим, что у нас отсутствует возможность изменить метод greet объекта Foo, чтобы включить в него вызов dojo.pub-lish, изза наличия какихто внешних обстоятельств, которые препятствуют этому, например когда программный код не является вашей собственностью или не должен изменяться.


Это не причина для беспокойств – мы можем использовать другую функцию, dojo.connectPublisher, которая будет выполнять публикацию события всякий раз, когда оно происходит:
function Foo() {
this.greet = function() {
console.log("Hi, I'm foo");
}
}
function Bar() {
this.greet = function() {
console.log("Hi, I'm bar");
}
}
var foo = new Foo;
var bar = new Bar;
var topic = "/dtdg/salutation";
dojo.subscribe(topic, bar, "greet");
dojo.connectPublisher(topic, foo, "greet");
foo.greet();

Суть этого заключительного примера состоит в том, что функция dojo.connectPublisher позволила добиться тех же результатов, что и добавление вызова dojo.publish в метод greet, но без изменения исходного программного кода. В этом смысле объект foo является косвенным источником уведомлений и даже не подозревает, что вообще осуществляется какоето взаимодействие. С другой стороны, объект Bar, как подписчик на получение уведомления, требует явного знания схемы взаимодействий. По существу, это противоположный случай типично го использования функции dojo.connect, когда объект, предоставляющий информацию для обмена, должен явно знать о других объектах или функциях, которые играют роль «целей» соединения..



Оцените статью: (0 голосов)
0 5 0

Статьи из раздела Dojo на эту тему:
Использование замыканий с функцией dojo.connect
Нормализация событий и клавиатуры
Обработчики событий
Распространение событий