Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Организация работы событий (http://www.flasher.ru/forum/showthread.php?t=140798)

koIIImarik 08.06.2010 15:30

Организация работы событий
 
Здравствуйте.

Интересует следующий вопрос, скорее даже нюанс проектирования приложений:

1) Допустим, у нас есть какой-то объект, который генерирует большое количество событий (больше 10).
2) Большинство из этих событий однотипные и через эти события не должны передаваться параметры.
3) Через некоторые события должны передаваться параметры, которые неотрывно привязаны к событию. Под параметрами, в данном контексте, я понимаю public переменные, которые можно считывать наподобие свойств target и/или delta у MouseEvent.

Возникает вопрос: что делать, создавать 10 классов для каждого типа событий, каждое событие которого бы обладало только теми параметрами (читай открытыми свойствами), которые принадлежат к данному типу события, или целесообразней, в целях «не плодить большого количества классов и сэкономить время» сделать 1 класс события, указать в нём все свойства, которые могут быть необходимы для событий и устанавливать значения только для тех событий, которые будут нужны в каждом конкретно случае?

Я, пока, склоняюсь ко 2-му способу, ведь, на сколько я понимаю, даже в MouseEvent сделано таким образом, что свойство delta доступно и при событиях CLICK, MOUSE_DOWN и т.п., хотя фактически оно необходимо только у события MOUSE_WHEEL.

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

Вот такие вот дела.

fljot 08.06.2010 16:32

Только не public переменные, а геттеры

Psycho Tiger 08.06.2010 16:37

Цитата:

Сообщение от fljot (Сообщение 913929)
Только не public переменные, а геттеры

Сомнительно.


А я дурак, я делаю одно событие с var info:Object={} куда пишу всё что сдумается. :D

На самом деле просто посмотри, что ты там передаешь с событием. Например, количество игроков онлайн, открытые двери и год после рождества Христова. По сути, 3 разных переменных - totalOnline, openDoors, year, но ведь можно передать просто intValue, а в комментариях написать мол "а тут нам приходит..."

koIIImarik 08.06.2010 16:47

2 PsyhoTiger:
Мне кажется ваш подход в корне не правилен.

Цитата:

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

Плюс непонятные названия переменных будут усиливать неразбериху.

2 fljot:
Цитата:

Только не public переменные, а геттеры
Это кому-как удобнее, я не люблю тру геттер/сеттер методы (аля get myProp), да и писать в коде события гетеры сеттеры я пока не вижу смысла, мне кажется это только увеличит количество кода и усложнит класс события. Не вижу пока смысла «защищать» возможность изменения переменных у события, так как это событие будет использоваться только в 1 месте (приемник события).

Psycho Tiger 08.06.2010 16:56

Да.
Какие плюсы я вижу: типизация и использование одного события для многих задач.
В коде:
Код AS3:

private function eventHandler(event:MyEvent):void{
//ожидаем с событием количество единиц дерева
super.totalWood=event.intValue;
}

Конечно, если значений переменных много - а ля intValue1,intValue2...etc, или вообще приходит вектор - там просто запутаться. Но тогда можно сразу в хендлере вынести в локальные переменные, а ещё лучше для таких событий сделать отдельное событие.

Я не говорю, что мой вариант лучший - но он вполне имеет право на жизнь. Но, как я уже сказал, я всё равно пользуюсь одним Object`ом )

koIIImarik 08.06.2010 17:25

Каждому — своё, но мне кажется, что вариант с object, в этом случае, не имеет права на жизнь (я понимаю, что это звучит категорично, но мне кажется, что хорошо когда нам компилятор будет сам подсказывать, к каким переменным можно обратиться, а к каким — нет + хорошие названия переменных улучшают читабельность кода).

Такие моменты, на мой взгляд, становятся важны когда работаешь в команде или создаёшь что-то, чем будут пользоваться другие люди, если работаешь один, то на это можно забить, но это не значит, что так нужно/следует поступать.

etc 09.06.2010 10:54

Цитата:

Сообщение от fljot (Сообщение 913929)
Только не public переменные, а геттеры

Досточно public-ов. От геттеров проку нет, событие всё равно клонируется постоянно.

fljot 09.06.2010 16:12

Цитата:

Сообщение от etc (Сообщение 914122)
Досточно public-ов. От геттеров проку нет, событие всё равно клонируется постоянно.

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

etc 09.06.2010 17:59

Цитата:

Сообщение от fljot (Сообщение 914234)
Клонируется то клонируется, но это при бабблинге или в разных обработчиках. Но ведь можно изменить данные, если кто-то его передиспатчит, или внутри одного обработчика, или при передаче ("по ссылке") куда-то.

И что? Если вы хотите наступить на грабли, вы на них наступите. Причем самостоятельно.

Psycho Tiger 09.06.2010 18:55

Да, etc прав. Вся инкапсуляция и тому подобное было сделано ради защиты от дураков. Защиты от идиотов же не существует. Я найду способ сломать событие и с геттерами. Например, остановлю его.

mikhailk 09.06.2010 19:18

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

Продал твой фермер корову вместе с попоной на колбасу, сервер вернул информацию о том, что сделка акцептована, ты сформировал хорошее такое событие с xml-кой внутри, прогнал его не задумываясь по всем объектам (касса, хлев, склад, производственный план, что там еще), и все счастливы. Каждый объект взял из него то, что его касается, и все аккуратненько и синхронно обновилось.

Но, это лично мне так нравится.
Совсем не обязательно, что так правильно.

Psycho Tiger 09.06.2010 20:11

mikhailk, у нас речь не о обмене сервер-клиент, а о событиях в самой флешке. Наследники flash.events.Event так сказать)

Mur4ik 09.06.2010 22:36

Если все события генерирует один объект, то можно предположить, что все параметры передаваемые через события как то связаны или имеют принадлежность к какой то сущности. Можно сделать и один класс события в котором будет один параметр представляющий собой класс, который содержит в себе нужные строго типизированные свойства (т.н. value object). Т.е решение подобное ому как делает Psycho Tiger, только не в ущерб типизации, автокомплита и т.д.

koIIImarik 09.06.2010 22:44

2 Mur4ik:
Как мне кажется, ваш вариант подходит в том случае, если этот объект с типизированными переменными будет использоваться ещё где-нибудь (допустим его будут передавать в качестве параметра для создания объектов на основе этого объекта), иначе, как мне кажется, нет смысла переносить список переменных из Event объекта в какой-то другой объект, потому что по сути добавляется только 1 промежуточный этап на пути доступа к переменным.

Mur4ik 09.06.2010 22:58

Не спорю.
Просто если параметры передаваемые событием связаны, то мне удобнее видеть их в одном объекте, который их характеризует, вместо того чтоб в классе события создавать 5-10 параметров, с которыми работа только усложняется, особенно в случае когда нужно передать большую часть из этих параметров (имеется ввиду инициализация события). А вот имея один-два типизированных объекта все становится прозрачнее и удобнее, ИМХО.

switcher! 10.06.2010 13:50

Цитата:

Сообщение от etc (Сообщение 914122)
Досточно public-ов. От геттеров проку нет, событие всё равно клонируется постоянно.

Цитата:

Сообщение от fljot (Сообщение 914234)
Клонируется то клонируется, но это при бабблинге или в разных обработчиках...

что-то я, видимо, не понимаю. Не замечал, чтобы событие при баблинге клонировалось. По крайней мере, в дисплейобджектах.
Если все правильно про клонирование, то как/когда это происходит при нативном всплытии события? :o

Вот пример того, что наблюдаю я:
Код AS3:

package
{
        import flash.display.Sprite;
        import flash.events.Event;
 
        public class Example extends Sprite
        {
                private var _event:MyEvent;
 
                function Example() {
                        super();
 
                        var s1:Sprite = new Sprite();
                        var s2:Sprite = new Sprite();
                        var s3:Sprite = new Sprite();
 
                        super.addChild(s1);
                        s1.addChild(s2);
                        s2.addChild(s3);
 
                        s1.addEventListener(Event.CHANGE, this._test1);
                        s2.addEventListener(Event.CHANGE, this._test2);
 
                        s3.dispatchEvent(new MyEvent(Event.CHANGE, true));
                }
 
                private function _test1(e:MyEvent):void {
                        trace(e.info); //10
                        trace(this._event === e); //true
                }
 
                private function _test2(e:MyEvent):void {
                        trace(e.info); //5
                        e.info = 10;
                        this._event = e;
                }
        }
}

Код AS3:

package  
{
        import flash.events.Event;
 
        public class MyEvent extends Event
        {
                public var info:int;
 
                function MyEvent(type:String, bubbles:Boolean = false, info:int = 5, cancelable:Boolean = false) {
                        super(type, bubbles, cancelable);
 
                        this.info = info;
                }
 
                // монжно раскомментить - трейсы те же.
                /*override public function clone():Event {
                        return new MyEvent(super.type, super.bubbles, 20)
                }*/

        }
}


Psycho Tiger 10.06.2010 15:40

Попробуйте сделать
Код AS3:

super.addEventListener(YourEvent.EVENT, super.dispatchEvent);


switcher! 10.06.2010 17:31

да, при редиспатче поюзанного эвента - он клонируется. Видимо, идет проверка а-ля:
Код AS3:

if (event.$target) //внутренний internal таргет
{
        event = event.clone();
}

Благо EventDispatcher и Event лежат в одном пакете. Однако, это домыслы, ибо неизвестно, что в тамошних сях записано.

Но не суть. Из контекста приведенных мною цитат ниразу не понятно, что идет редиспатч. Скорей наоборот - речь об обычном распространении события. А при нем, как показывают тесты, клонирования события от обработчика к обработчику не происходит.
Собственно, по этому поводу я и ожидал комментариев.

fljot 10.06.2010 17:34

Хм да, я тоже несколько удивлён=) etc, не разъяснишь?

Psycho Tiger 10.06.2010 17:57

Событие клонируется при нативном EventDispatcher::dispatchEvent`е.

switcher! 10.06.2010 18:20

Цитата:

Сообщение от Psycho Tiger (Сообщение 914515)
Событие клонируется при нативном EventDispatcher::dispatchEvent`е.

Событие клонируется при повторном диспатче использованного эвента. При обычном распространении события - оно не клонируется. И не важно вызвал метод Sprite или EventDispatcher.

dimarik 10.06.2010 18:27

Вы имеете ввиду, если вызвать метод EventDispatcher#dispatchEvent, то внутри него произойдет event.clone();

Psycho Tiger 10.06.2010 18:30

Цитата:

Сообщение от switcher! (Сообщение 914521)
Событие клонируется при повторном диспатче использованного эвента. При обычном распространении события - оно не клонируется. И не важно вызвал метод Sprite или EventDispatcher.

Вы мои слова повторили. Только вот у Sprite`а нету метода dispatchEvent.
И вот только оно клонируется всегда, даже при первом вызове dispatchEvent`а.

Короче, то что сказал dimarik.

switcher! 10.06.2010 18:51

Цитата:

Сообщение от Psycho Tiger (Сообщение 914524)
Вы мои слова повторили

можно на "ты". Я флеймовую темку почитал по этому поводу. Просветился -)))

Цитата:

Сообщение от Psycho Tiger (Сообщение 914524)
Только вот у Sprite`а нету метода dispatchEvent.

я где-то сказал, что Sprite определяет dispatchEvent?

Цитата:

Сообщение от Psycho Tiger (Сообщение 914524)
И вот только оно клонируется всегда, даже при первом вызове dispatchEvent`а.

нет, клон это новый объект. Как тогда объяснить это, если dispatchEvent всегда создает клон:
Код AS3:

package
{
        import flash.display.Sprite;
        import flash.events.Event;
        import flash.events.EventDispatcher;
 
        public class Example extends Sprite {
                private var _event:Event;
 
                function Example() {
                        super();
 
                        this._event = new Event(Event.CHANGE);
 
                        var s3:EventDispatcher = new EventDispatcher();
                        s3.addEventListener(Event.CHANGE, this._test1);
                        s3.dispatchEvent(this._event);
                }
 
                private function _test1(e:Event):void {
                        trace(this._event === e); //true
                }
        }
}

Цитата:

Сообщение от Psycho Tiger (Сообщение 914524)
Короче, то что сказал dimarik.

имо, dimarik задал вопрос, а не выдвинул утверждение.

Psycho Tiger 10.06.2010 19:05

Ого, и вправду. Ошибался, спасибо, буду знать. А второе событие уже клон.

Видимо событие несёт в себе какой-то флаг а-ля isUsed, и раздваяйца оно только если событие уже было использовано.

Цитата:

я где-то сказал, что Sprite определяет dispatchEvent?
Не так понял. Во флеше все методы виртуальные, поэтому эта фраза по сути смысловой нагрузки для меня не несёт. Вот и додумал =)

switcher! 10.06.2010 20:10

Цитата:

Сообщение от Psycho Tiger (Сообщение 914536)
А второе событие уже клон.

ага.
Собственно, под эгидой этого топика я надеялся избавиться от геттеров в сложных событиях (наступление которого ожидают несколько объектов/обработчиков). Но, видимо - не судьба.
"Не клонируется", раз... "Не клонируется", два... "Не клонируется", три... Пр...:D

P.S. оффтоп. Даный топик имеет тег "Лень", по которому в поиске пробивается только этот топик. Забавно ))

Psycho Tiger 10.06.2010 20:24

switcher, геттеры (ридонли) - это лишь перестраховка в 99% случаев, чтобы случайно что-нибудь не изменить - чисто по запарке.

switcher! 10.06.2010 20:59

разумеется, но я эту "перестраховку" вывел в стандарт. В простых нотификациях можно и открытыми переменными обойтись, ибо плевать, что обработчик с объектом события сделает. Оно (событие) ему только и предназначается.
Однако в сложных, когда подписчиков много, я не хочу держать в голове: что я могу, а что не могу делать с полями объекта события. Я хочу быть уверенным, что объект как неизменный штамп события дойдет до адресата в том виде, в каком он изначально описывает событие.

А так, конечно, можно все переменные пабликами делать, из детей родителями управлять и т.д. => главное, "чисто по запарке" не запутаться :)

P.S. Я не занимаюсь миссионерством. Если кого-то сей подход не устраивает, пожалуйста, пожалуйста...

dimarik 10.06.2010 21:59

Клонирование события происходит при наличии у диспетчера parent и если выставлен флаг bubbles?

switcher! 10.06.2010 22:50

неа, пока установлен только один случай, когда происходит клонирование события. Это повторный диспатч того же объекта события.

dimarik 10.06.2010 23:39

ок.

Код AS3:

var event:Event = new Event(Event.CHANGE, true);
super.dispatchEvent(event);
super.dispatchEvent(event); // диспетчеризация клона

Так?

switcher! 10.06.2010 23:58

в яблочко

dimarik 11.06.2010 00:04

Собственно, резюме. Если у события target != null, то при диспетчеризации оно клонируется.

В моем примере флаг bubbles не имеет значения.

switcher! 11.06.2010 00:18

Цитата:

Сообщение от dimarik (Сообщение 914600)
Если у события target != null, то при диспетчеризации оно клонируется.

ага

dimarik, раз уж такое дело - хотелось бы знать, реализация клонирования эвента в ваших моделях(Data) на каждом уровне "всплытия" (при наличии обработчиков) целесообразна? Так и задумывалось? Или проглядели, что в нативной системе эвент при баблинге не клонируется?

(я должен был спросить, вдруг прокатит :D)

dimarik 11.06.2010 00:46

Уточнение. Клонирование скорее всего необходимо при event.target != null && event.target != this.

В нативной системе при диспатче (напр., Event.ADDED) не дергается dispatchEvent вообще. Соответственно, такая проверка не вызывается и событие не клонируется. У нашей Data клонируется, как Вы и указали, если среди прочих условий соблюдено parent.hasEventListener(event.type). И target клона устанавливается текущим диспетчером.

switcher! 11.06.2010 01:11

Цитата:

Сообщение от dimarik (Сообщение 914603)
Уточнение. Клонирование скорее всего необходимо при event.target != null && event.target != this.

в этом примере:
Цитата:

Сообщение от dimarik (Сообщение 914597)
Код AS3:

var event:Event = new Event(Event.CHANGE, true);
super.dispatchEvent(event);
super.dispatchEvent(event); // диспетчеризация клона


и объект события один и тот же, и объект его испускающий один и тот же. Но при этом событие все равно клонируется. Так что второе условие, скорей всего - не подходит.

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

dimarik 11.06.2010 01:45

Цитата:

Сообщение от switcher! (Сообщение 914605)
Так что второе условие, скорей всего - не подходит.

Да, мне понятна Ваша мысль. Я там приписал мелким шрифтом, что "клонирование скорее всего необходимо" при таких-то условиях )

Я пытаюсь рассуждать как должно быть, а не как это реализовано в FP. Если мы поймем зачем нужно клонирование событий, то его можно реализовать оптимальным способом. Клонирование само по себе необходимо для предотвращения изменений объекта по ссылке. Сравните: передали методу массив и он модифицировал его. А в вызывающем методе Вы предполагали, что он не изменится. Выход - либо передаем клон, либо в вызванном методе создаем клон.

С другой стороны, конкретно в области event flow при выполнении диспетчеризации у событийного объекта должен быть установлен target того, кто его испустил. Здесь получается, что если бы не было клона, то неожиданно у всех предыдущих объектов-приемников поменялся бы event.target по ссылке. Но я диспатчу событие от того же передатчика. Здесь мне не нужен клон.

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

Кстати, иногда в проектах встречаю подобное
Код AS3:

function handler(event:Event):void {
    // что-то тут делают
    dispatchEvent( event.clone() )
}

Вот получается, что напрасно клонируют, оно само склонируется при ре-диспатче.


Цитата:

По остальному: так ведь у вас целевой эвент не баблится непосредственно. Для этого у него есть эвент-обертка. Но вы все равно клонируете целевой эвент на всех уровнях (при наличии слушателей), который вообще не диспатчится. Он тащится наверх эстафетой из оберток. Смысл его клонировать?
Реверс инженеринг или Вы начали работать у нас? )
BloodHound'а спросите, его детище. Я вообще использую в модели дисплей-объекты.

etc 11.06.2010 09:53

Цитата:

Сообщение от switcher! (Сообщение 914575)
P.S. Я не занимаюсь миссионерством.

Нет, вы просто занимаетесь фигней. Ну это примерно как постоянно ходить в перчатках сварщика, чтобы затраховаться от засовывания рук в печку.

switcher! 11.06.2010 14:26

Цитата:

Сообщение от etc (Сообщение 914652)
Нет, вы просто занимаетесь фигней. Ну это примерно как постоянно ходить в перчатках сварщика...

Я не использую геттеры в эвентах "постоянно". К тому же, вы сами не редко руководствуетесь в программировании правилом "шаг влево, шаг вправо - расстрел". И я не вижу ничего зазорного в использовании геттеров, особенно, когда производительность не критична.
Вам удобнее так, мне - иначе. Вот и весь сказ :)

Цитата:

Сообщение от dimarik (Сообщение 914612)
Я пытаюсь рассуждать как должно быть...

Разумно.
Однако, думаю, это защита от дурака. Т.е., например, первое распространение события еще не закончилось, а прогер уже задиспатчил эвент от того же объекта повторно. Допустим, без "пузырей". В итоге у события повисает фаза "цели". И когда поток исполнения программы возращается к баблингу первого события, уже имеется косяк: event.eventPhase === 2. Сомневаюсь, что такие мелочи проверяются перед каждым обработчиком.

Цитата:

Сообщение от dimarik (Сообщение 914612)
Реверс инженеринг или Вы начали работать у нас? )

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

dimarik 11.06.2010 16:46

Ах, вот как! Следовательно. клонирование необходимо так же и для того, чтобы фазу на попортить.

А не напомните, где тот узкий участок был рассмотрен в темах?


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

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