Форум Flasher.ru
Ближайшие курсы в Школе RealTime
Список интенсивных курсов: [см.]  
  
Специальные предложения: [см.]  
  
 
Регистрация Блоги Правила Справка Пользователи Календарь Поиск рулит! Сообщения за день Все разделы прочитаны
 

Вернуться   Форум Flasher.ru > Блоги > f.g.programmer

Оценить эту запись

Simple Event Controller

Запись от f.g.programmer размещена 05.01.2011 в 15:32
Обновил(-а) f.g.programmer 07.01.2011 в 00:42 (добавил применимость)

Simple Event Controller

Класс для упрощения работы с подпиской-отпиской обработчиков событий.

Пример использования
Код AS3:
// создание объекта управляющего обработчиками, обычно в конструкторе
_sec = new SEC();
 
// добавление обработчиков
_sec.add(obj1, “event1”, event1Handler);
_sec.add(obj1, “event2”, event2Handler);
_sec.add(obj2, “event1”, event1Handler);
_sec.add(obj2, “event2”, event2Handler);
 
// добавление обработчика с дополнительными параметрами
_sec.add(obj1, “event3”, Action.create(event3Handler, 42, “lev”));
private function event3Handler(e:Event, param1:int, param2:String):void {
}
 
// удаление конкретного обработчика
_sec.remove(obj1, “event1”, event1Handler);
 
// удаление всех обработчиков obj1, включая с дополнительными параметрами
_sec.remove(obj1);
 
// удаление всех обработчиков
_sec.remove();


Применимость

1. Для упрощения отписки с защитой от дурака
т.е. вместо
Код AS3:
url_loader.removeEventListener(IOErrorEvent.IO_ERROR, oErrorHandler);
url_loader.removeEventListener(SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
url_loader.removeEventListener(ProgressEvent.PROGRESS, progressHandler);
url_loader.removeEventListener(Event.COMPLETE, completeHandler);
используем
Код AS3:
// подписка
_sec.add(url_loader, IOErrorEvent.IO_ERROR, oErrorHandler);
_sec.add(url_loader, SecurityErrorEvent.SECURITY_ERROR, securityErrorHandler);
_sec.add(url_loader, ProgressEvent.PROGRESS, progressHandler);
_sec.add(url_loader, Event.COMPLETE, completeHandler);
// отписка
_sec.remove(url_loader);
// или, если контроль осуществляется только над одним объектом
_sec.remove();
2. Для упрощения отписки от условных, неопределённых обработчиков
в процессе работы обработчики одного события могут меняться, т.е. в разных частях класса при разных условиях могут вызываться такие строки
Код AS3:
// в одном месте
button1.addEventListener(Mouse.CLICK, clickHandler1);
button2.addEventListener(Mouse.CLICK, clickHandler2);
// в другом месте
button1.addEventListener(Mouse.CLICK, clickHandler2);
button2.addEventListener(Mouse.CLICK, clickHandler1);
чтобы гарантировано отписаться, нужно вызвать removeEventListener для всех возможных обработчиков,
Код AS3:
button1.removeEventListener (Mouse.CLICK, clickHandler1);
button2.removeEventListener (Mouse.CLICK, clickHandler2);
button1.removeEventListener (Mouse.CLICK, clickHandler2);
button2.removeEventListener (Mouse.CLICK, clickHandler1);
при использовании контроллера
Код AS3:
// подписка
_sec.add(button1, Mouse.CLICK, clickHandler1);
_sec.add(button2, Mouse.CLICK, clickHandler2);
_sec.add(button1, Mouse.CLICK, clickHandler2);
_sec.add(button2, Mouse.CLICK, clickHandler1);
// отписка
_sec.remove();
3. Слушатель с параметром
пример, FD проект




Файл SEC.as
Код AS3:
package
{
   import flash.events.IEventDispatcher;
   import Action;
 
   public class SEC
   {
       private var _records:Vector.<SECRecord>;
 
       public function SEC()
       {
           _records = new Vector.<SECRecord>();
       }
 
       /// добавление
       public function add(obj:IEventDispatcher, type:String, listener:Function, useCapture:Boolean = false, priority:int = 0):void {
           var rs:Vector.<SECRecord> = _records
               .filter(Action.create(isObject, obj))
               .filter(Action.create(isType, type))
               .filter(Action.create(isListener, listener))
               .filter(Action.create(isUseCapture, useCapture));
           if (rs.length == 0) {
               _records.push(new SECRecord(obj, type, listener, useCapture));
               obj.addEventListener(type, listener, useCapture, priority, false);
           }
       }
 
       /// удаление
       public function remove(obj:IEventDispatcher = null, type:String = null, listener:Function = null, useCapture:* = undefined):void {
           var rs:Vector.<SECRecord> = _records.slice();
           if (obj) {
               rs = rs.filter(Action.create(isObject, obj));
               if (type) {
                   rs = rs.filter(Action.create(isType, type));
                   if (listener != null) {
                       rs = rs.filter(Action.create(isListener, listener));
                       if (useCapture is Boolean) {
                           rs = rs.filter(Action.create(isUseCapture, useCapture as Boolean));
                       }
                   }
               }
           }
           for each(var record:SECRecord in rs) {
               _records.splice(_records.indexOf(record), 1);
               record.obj.removeEventListener(record.type, record.listener, record.useCapture);
           }
       }
 
      private function isObject(item:SECRecord, index:int, vector:Vector.<SECRecord>, obj:IEventDispatcher):Boolean {
           return item.obj === obj;
       }
       private function isType(item:SECRecord, index:int, vector:Vector.<SECRecord>, type:String):Boolean {
           return item.type === type;
       }
       private function isListener(item:SECRecord, index:int, vector:Vector.<SECRecord>, listener:Function):Boolean {
           return item.listener === listener;
       }
       private function isUseCapture(item:SECRecord, index:int, vector:Vector.<SECRecord>, useCapture:Boolean):Boolean {
           return item.useCapture === useCapture;
       }
 
 
   }
 
}
import flash.events.IEventDispatcher;
class SECRecord {
   public var obj:IEventDispatcher;
   public var type:String;
   public var listener:Function;
   public var useCapture:Boolean;
   public function SECRecord(obj:IEventDispatcher, type:String, listener:Function, useCapture:Boolean)
   {
       this.obj = obj;
       this.type = type;
       this.listener = listener;
       this.useCapture = useCapture;
   }
}


Файл Action.as
Код AS3:
package
{
   public class Action
   {
       /// создание функуии с меньшим количеством параметров или без, подстановка в том же порядке в конец
       public static function create(fun:Function, ...params):Function {
           return new Action(fun, params).call;
       }
 
       private var _fun:Function;
       private var _args:Array;
       public function Action(fun:Function, args:Array)
       {
           _fun = fun;
           _args = (args) ? args.slice() : [];
       }
       public function call(...args):* {
           return _fun.apply(null, args.concat(_args));
       }
   }
}
Вложения
Тип файла: zip SEC.ZIP (11.8 Кб, 269 просмотров)
Всего комментариев 13

Комментарии

Старый 05.01.2011 19:24 incvizitor вне форума
incvizitor
 
Аватар для incvizitor
Вот интересно. Те кто каждый день задаються вопросом "а как передать параметры в слушатель?", смогут понять этот код?)

А вообще, код весьма не плохой)
Старый 05.01.2011 20:29 NumpuT вне форума
NumpuT
И как долго писался код?
Старый 05.01.2011 22:24 f.g.programmer вне форума
f.g.programmer
 
Аватар для f.g.programmer
Цитата:
Вот интересно. Те кто каждый день задаються вопросом "а как передать параметры в слушатель?", смогут понять этот код?)
В принципе, чтобы его использовать не нужно его понимать )

Цитата:
И как долго писался код?
Первоначальный вариант где-то пол часа, но потом многократно полировался.
Старый 06.01.2011 01:57 mayakwd вне форума
mayakwd
 
Аватар для mayakwd
по-моему это пятое колесо.
Старый 06.01.2011 02:52 TanaTiX вне форума
TanaTiX
 
Аватар для TanaTiX
Цитата:
по-моему это пятое колесо.
А помоему, хотя я подобным менеджером ни разу не пользовался, это может быть очень удобным, в зависимости от поставленных задач. Так, если в проекте очень много зависит от событий и даже групп событий, то я бы от такого инструмента не отказался. В других ситуациях использовал бы вряд ли. В любом случае идея достойная внимания.
Старый 06.01.2011 03:47 Котяра вне форума
Котяра
 
Аватар для Котяра
silin уже описывал глобальный бродкастер и в ас2 такой был. это бывает удобно, но с другой стороны это ломает инкапсуляцию.
в КОНКРЕТНОМ проекте, я так же делегирую на главный контроллер все события, то же делает и мате/пюре итп, но при расширении и реиспользовании это очень неудобно.
Но, ещё раз повторюсь, это может быть удобно в КОНКРЕТНОМ случае.
Старый 06.01.2011 03:51 Котяра вне форума
Котяра
 
Аватар для Котяра
дуализм: "чистый ооп" / "да задолбали эти абстракции - лучше сделать как быстрее".
Выбор программиста (не кодера) - по конкретной задаче. Кодер должен выбирать ООП.
Дао сложен, и понять себя программистом, но не кодером есть дао.
ps считаю себя на пути к дао, но никак не познавшим))))
Обновил(-а) Котяра 06.01.2011 в 03:55
Старый 06.01.2011 12:36 -De- вне форума
-De-
 
Аватар для -De-
Мне не нравится, что на каждое добавление/удаление надо гарантированно 4 раза обойти этот вектор. А он может быть не маленький.
Старый 06.01.2011 12:57 f.g.programmer вне форума
f.g.programmer
 
Аватар для f.g.programmer
Цитата:
на каждое добавление/удаление надо гарантированно 4 раза обойти этот вектор. А он может быть не маленький.
На сколько немаленьким? Я использую его для локального контроля, обычно одновременно прослушивается не больше десятка событий от различных объектов. Но, возможно, для глобального контроля с сотнями событий это не лучшее решение.
Старый 06.01.2011 13:05 f.g.programmer вне форума
f.g.programmer
 
Аватар для f.g.programmer
Кроме того, в первый раз обходится весь массив, второй раз, обходится значительно укороченный массив из записей принадлежащих одному объекту, третий раз обходятся обработчики одного события конкретного объекта, и на четвёртый обход остаётся не больше двух элементов.
Старый 06.01.2011 13:39 -De- вне форума
-De-
 
Аватар для -De-
Да, не 4, ближе к 1. Можно легко переделать на ровно 1 (и не рожать вообще при этом Action). Но несколько смущает вообще обход. Ну хотя согласен, наверное редко когда тормоза проявятся.
Я бы завёл Dictionary с ключаеми из обьектов, которые слушаем и значениями - векторами типа _records (ну и там obj уже тогда не надо будет хранить). На один обьект реально не вешают и десятка слушателей, там уже обход оправдан. Возможно даже быстрее, чем если сделать полную иерархию, где обход не нужен и всё по ключу проверяется. Но только я ничего не сделал такого %))
Старый 06.01.2011 16:25 Psycho Tiger вне форума
Psycho Tiger
 
Аватар для Psycho Tiger
Недурно.
Старый 06.01.2011 20:25 etc вне форума
etc
 
Аватар для etc
Не нужно.
 
Последние записи от f.g.programmer

 


Часовой пояс GMT +4, время: 20:07.


Copyright © 1999-2008 Flasher.ru. All rights reserved.
Работает на vBulletin®. Copyright ©2000 - 2020, Jelsoft Enterprises Ltd. Перевод: zCarot
Администрация сайта не несёт ответственности за любую предоставленную посетителями информацию. Подробнее см. Правила.