Форум Flasher.ru

Форум Flasher.ru (http://www.flasher.ru/forum/index.php)
-   ActionScript 3.0 (http://www.flasher.ru/forum/forumdisplay.php?f=83)
-   -   Должен ли вид быть IEventDispatcher'ом? (http://www.flasher.ru/forum/showthread.php?t=133323)

wvxvw 02.12.2009 14:40

Должен ли вид быть IEventDispatcher'ом?
 
Мы тут недавно поспорили по этому поводу, но, хотелось бы услышать еще мнения.
Я думаю, что нет, другая сторона думаeт, что да.
Мои доводы:
Примеры классы Graphics и BitmapData, которые вполне подпадают под описание "вида" по моему мнению. + другие "самодельные" виды, типа как например управление HTML элементами страницы, или запись файла, который тоже может быть видом для другого приложения.
(Все, опять же только мое мнение).

Доводы другой стороны:
Флеш на 99% рассчитан на работу с дисплей объектами, и подписываться на события от них - это как бы в порядке вещей, и вообще удобно. + возможность диспатчить в них события типа "бродакаст" делает подход к проблеме несколько более универсальным. + одинаковый подход к работе с видом, т.как любой вид можно представить, как один и тот же интерфейс, не вдаваясь в конкретику. + это несколько упрощает планирование. Так, например, если апдейты во вью не моментальные, то мы легко решаем проблему асинхронности апдейтов.

Вобщем, хотелось бы услышать ваши мнения.

SamFR 02.12.2009 15:27

Мне кажется, что, если мы говорим всё-таки о флеше, то здесь как минимум 90% видов наследуют от класса, реализующего этот интерфейс. Поэтому поводом к неиспользованию IEventDispatcher могут стать только существенные недостатки, которые это использование за собой повлечёт. Какие преимущества даёт использование этого интерфейса, вы только что подробно рассказали :) Серьёзных недостатков я не вижу. Да, идеологически немного неправильно, но только немного, и проявляться это будет нечасто. Так что, думаю, должен (вернее, стоит).

gloomyBrain 02.12.2009 16:49

Я думаю да, конечно.
Любой вид должен имплементить этот интерфейс
Цитата:

идеологически немного неправильно
Не согласен. Если вы что-то видите, вы должны уметь это "потрогать".

bicubic_bublic 02.12.2009 17:25

не соглашусь что BitmapData подпадает под описание "вида". это объект с данными, о чем нам и сигнализирует суффикс Data.

Graphics же - просто интерфейс (тоже не "вид")

divinus 02.12.2009 18:34

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

wvxvw 02.12.2009 19:57

Просто когда мы это примеряем на флеш, то нам подход с дисплей объектами кажется очевидным, но, флеш это все таки не единственое место, где MVC имеет место быть :), в том же PHP существует точно такая же парадигма, и там как-то никто не предполагает, что вид будет дисатчить события обратно... Как правило предполагается в него просто сеттить чего-нибудь.

Да, может быть Graphics не самый удачный пример, птотому что он не расширяемый, а вот BitmapData вполне, как на мой взгляд может выступать в качестве вида - банальный пример:
Рисуем графику в битмапдату и передаем ее серверу на сохранение. В этом случае нашим видом будет битмапдата... Как бы интерфейс он же не обязан быть с пользователем, он может быть и с другой программой.

Gaen 02.12.2009 22:33

А через что кроме вида можно получать события от пользователя? Лишив вид возможности рассылать события, мы лишаем приложение всякой интерактивности.
Если же вид является просто отображением, а не интерфейсом, то тогда он вполне может обойтись без рассылки событий.

mayakwd 02.12.2009 22:42

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

BlooDHounD 02.12.2009 23:23

wvxvw, что-то не вяжется твоя теория о том, что BitmapData - это представление. в твоей схеме представлением является сервер :) контроллер заполнил модель ( BitmapData ) и отдал представлению ( сервер ).

а по поводу IEventDispatcher... необязательно представление должно его реализовывать. просто в АС3 у тебя не получится иначе :) зато в том же пыхе, у тебя это получается. хотя если результатом работы скрипта является HTML, то в итоге ты получишь IEventDispatcher только браузеровский.

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

wvxvw 02.12.2009 23:40

Ну битмапдата, имелась в виду, например, такая ситуация:
У нас есть русунок, есть его представление в векторном виде - это бишь модель. И есть его представление в виде пиксельной картинки. Эта картинка вообще не является частью интерфейса, например, карта, куда пользователь кликал за время пребывания на сайте. С точки зрения сервера картинку можно рассматривать как модель, но на клиенте это все таки будет вид ИМО.

И это я не против наличия свойств диспетчера в виде, я против того, чтобы, например контроллер вcегда предполагал, что вид является диспатчером. Т.е. должен ли контроллер:
Код:

// достаточно ли делать так
view.dispatchEvent(new Event("update"));
// или все-таки так
if (view is IEventDispatcher) view.dispatchEvent(new Event("update"));
else view.update();


BlooDHounD 03.12.2009 00:10

Цитата:

Сообщение от wvxvw
У нас есть ... представление ... - это бишь модель

неее ) давай не будем натягивать мифические абстракции. рисунок это представление, на основании которого ты по событию можешь сделать ещё одну модель при помощи контроллера.
Цитата:

И это я не против наличия свойств диспетчера в виде, я против того, чтобы, например контроллер вcегда предполагал, что вид является диспатчером.
прочитай ещё раз последний абзац. а что касается кода, то он вообще не верен. никто не должен диспатчить чужие события. и уж тем более контроллер, который это событие ловить и должен по логике )

Gaen 03.12.2009 01:25

Цитата:

view.dispatchEvent...
А в каких случаях вообще требуется извне заставлять view запустить событие?
В данном случае скорее логично что представление получило событие от модели, обновилось и само послало об этом событие.

wvxvw 03.12.2009 02:14

Цитата:

А в каких случаях вообще требуется извне заставлять view запустить событие?
А то, что это случается на каждом шагу в дисплей листе флеш плеера - это вас как-то не смутило, да? (Blood, это и тебе ответ).
А каким образом по вашему происходят т.н. broadcast type events? Ну, например, Event.ADDED_TO_STAGE, Event.ENTER_FRAME и тому подобные? Или вы каким-то образом подпишитесь в виде (он же, пусть Sprite) на события от контроллера (он же Stage) до получения ссылки на контроллер? Как позвольте спросить?

etc 03.12.2009 09:11

wvxvw, это механика работы плеера, сам программер получает событие от самого чилда.

Но вот принудительно вызывать методы типа update и слать события извне — не комильфо. У нас, например, вообще снаружи отправлять события нельзя.

Котяра 03.12.2009 10:26

обычно у меня происходит нечто вроде этого:
Код AS3:

addModelViewer(view1,model1);
view1.addEventListener("button_click", funk1);
addModelViewer(view2,model1);

если view2 не диспатчит события, то на них и не подписываемся. хотя в моей реализации IView расширяет IEventDispatcher

alexcon314 03.12.2009 10:48

Для многопоточной среды ваш спор имел бы смысл, но не принципиальный. Можно так, можно этак, договоримся. Если и не договоримся, плевать, я лично долго не спорил бы)). Там хоть есть, о чем поговорить.
Плеер - однопоточная среда, все эти игрища с эвентами - сплошное запудривание мозга.
Диспатчить чужие события не хорошо, твой аргумент это подтверждение/следствие опять же однопоточности. Точнее, эти эвенты как раз и завязаны на общий поток исполнения.
В частности, я не понял, как наличие диспатчера в представлении поможет решить проблему асинхронности апдейта.

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

bicubic_bublic 03.12.2009 11:24

а однопоточная ли плеер среда? работал с Socket и наткнулся на то что иногда приходит новый пакет пока еще обрабатывается старый и параллельно начинает обрабатываться..

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

Котяра 03.12.2009 11:41

AS код - однопоточен, но внешние операции (прорисовка, загрузка внешних данных, слушание мыши и пр..) Может и идут в других потоках. Хотя не факт.

wvxvw 03.12.2009 13:28

Цитата:

Сообщение от alexcon314 (Сообщение 869964)
Диспатчить чужие события не хорошо, твой аргумент это подтверждение/следствие опять же однопоточности. Точнее, эти эвенты как раз и завязаны на общий поток исполнения.
В частности, я не понял, как наличие диспатчера в представлении поможет решить проблему асинхронности апдейта.

Цитата:

Сообщение от etc (Сообщение 869946)
wvxvw, это механика работы плеера, сам программер получает событие от самого чилда.

Но вот принудительно вызывать методы типа update и слать события извне — не комильфо. У нас, например, вообще снаружи отправлять события нельзя.

А почему плохо диспатчить чужие события? Я как-то не могу придумать ситуацию, когда это чем-то навредит. Если бы было плохо - dispatchEvent() был бы protected а не public...
И как бы события они скорее следствие того, что плеер, как програма - многопоточный, а язык не предусматривает такой возможности ИМО.

Gaen 03.12.2009 13:41

Объект диспатчит событие, когда хочет сообщить о чем-то, что произошло с ним или внутри него. Это понятно, логично и правильно.
А вот когда кто-то начинает управлять отсылкой событий через подставное лицо, сразу возникает куча вопросов. И первый из них - если что-то произошло в объекте А, то почему вдруг я узнаю это от Б?

wvxvw 03.12.2009 14:19

Тоесть пример с ентерфреймом вас не убедил? :)
Ну хорошо, такой пример:
У нас есть соединение с сервером, которое посылает команды клиенту.
Мы можем использовать следующие подходы:
Самый простой:
У класса соединения определяем все методы, которые можно вызвать.
- Недостатки, соответственно, отсутствие гибкости, возможно куча методов, многие из которых не будут вызываться никогда в некоторых сценариях и т.д.
У класса соединения есть свойство client и этот объект уже должен реализовывать методы, которые мы собираемся вызывать через удаленную процедуру.
- Недостатки: нужно создавать какие-то служебные объекты и, почти наверняка некоторые методы прийдется реализовывать в каждом из клиентов, или создавать целую иерархию таких клиентов с абстрактными классами... вобщем, мрак и куча лишнего кода...
Мы можем создать универсальный обработчик, в который мы будем передавать название или ссылку на нужный нам метод клиента + аргументы и надеятся на то, что обработчик их вызовет через отражение или еще как.
- Недостатки: клиент может не обработать сообщение вообще.

Изначально предполагается, что ссылку на класс "раздающий указания" мы не хотим или не можем по техническим причинам передать в классы которые слушают / выполняют указания. Потому что, например, получение такой ссылки повлечет за собой создание ненужных зависимостей.
Пример: Stage попадает в список зависимостей DisplayObject потому, что у DisplayObject есть свойство stage, но мы бы могли это избежать просто работая с событиями, которые нам stage диспатчил бы от имени получателя (таким образом не давая ссылку на самого себя).

alexcon314 03.12.2009 15:08

Что-то я не пойму твою мысль..
Значит, нам приспичило иметь объект А, который может диспатчить события, но от имени другого объекта В. Так. Хоршо.
Этот другой объект В ничего не знает и не дожен знать о существовании объекта А. Так.
Мы имеем таким образом, независимый от А В. Так. Тогда А получается зависимым от В, ибо нужна ссыль чтоб диспатчить. Так.
Не понял.
По-другому.
Имеем В, который диспатчит эвент. Так. Имеем А, которму пофик на всех. Так.
Но, что бы получить эвент, надо подписаться, значит А должен иметь ссыль на В.
Стало быть А, будь он сторонним рассыльщиком, или просто листенером должен иметь ссыль на В. Не понял.
Хорошо. Пусть есть С, который хочет получать эвенты от А. Но мы хитро диспатчим через В, ибо не хотим, чтобы С, знал про А. Так. Тогда имеем С с сылкой на В, и А с сылкой на В. С и А ничего не знают друг о друге. Так. Но А, тем не менее шлет эвенты С, правда С получает их от имени В, но тем не менее. Круто.
Так что ли?
А в чем должен был убедить пример с энтерфреймом? В том что так бывает, и даже неплохо работает?
значит А - это стейдж, В - это объект, у которого А "поддиспатчивает" энтерфрейм. Так. Значит, мы можем иметь С, который получает энтерфрейм от стейджа, и который о стейдже ничего не знает.
Так что ли?

BlooDHounD 03.12.2009 15:15

wvxvw, что в примере с энтерфрэймом могло меня убедить, и в чём?
я вообще не понимаю твои примеры. как в анекдоте:
Цитата:

ВасильИваныч: - Петька, приборы!
Петька: - ВасильИваныч!, 36!
ВасильИваныч: - Что 36?
Петька: - А что приборы?
enterFrame диспатчик сам объект. просто через презерватив. что-то типа этого:
Код AS3:

public override function addEventListener(type:String, listener:Function, useCapture:Boolean=false, priority:int=0, useWeakReference:Boolean=false):void {
        super.addEventListener( type, listener, useCapture, priority, useWeakReference );
        switch ( type ) {
                case Event.ENTER_FRAME:
                case Event.EXIT_FRAME:
                case Event.FRAME_CONSTRUCTED:
                // case: и остальные кейсы
                        _BROADCASTER.addEventListener( type, super.dispatchEvent, useCapture, priority, useWeakReference );
                        break;
        }
}

я практически уверен, что бродкасер там не собирает все дисплэйобджекты, что бы пробежаться по массиву и вызывать dispatchEvent.

и с передачей всех дисплэйобджектов бродкастеру, ссылок там ещё больше получается.

wvxvw 03.12.2009 16:10

alexcon314:
Да, практически так. Но немного запутано...
Есть А и Б, А создал Б и после его создания проделал еще какие-то свои операции и продиспатчил в Б собыия сигнализирующие о том, что эти операции были сделаны.
пример:
DispalyObjectContainer#addChild(child);
Наши варианты действий:
Мы можем у child вызвать метод onAdded() а можем проверить а не подписался ли child на "onAdded" и только в случае если подписался вызвать onAdded() о сыществовании которого мы можем до этого и не знать вообще. Второй вариант экономичнее и не обязывает child имплементить onAdded в обязательном порядке.
На это накладывается еще такой момент: мы не хотим позволять ребенку знать больше чем положено о его родителе, т.как не хотим давать ему какие-либо полномочия по управлению родителем. По этому мы продиспатчим в него событие от имени ребенка, ну или не важно, пусть даже target будет null, главное ссылку на родителя не давать.
Если вы задумаетесь о таком подходе к, например, stage - то это бы разом решило кучу непоняток с песочницами, неудаляемым загруженым контентом и т.п. Т.как в таком случае у ребенка не было бы ссылки на stage, и он бы не смог создать жесткие ссылки туда, куда ему лезть не разрешено...

BlooDHounD:
Я почему-то думаю, что там схема такая же, как и в IE6 (window.event). Т.е. имеется какой-то глобальный броадкастер к которому мы подписываемся когда подписываемся на тот же ентерфрейм. Почему я так думаю - потому что mx EventDispatcher был именно так организован, и я сомневаюсь, что схему переделали. И этот самый глобальный броадкастер именно диспатчит события от имени подписчика. Иначе мне тяжело представить, каким образом ентерфрейм наступал бы синхронно везде, да и вообще, откуда бы клип узнал, что ему нужно продиспатчить ентерфрейм?

ЗЫ. Анекдот был в оригинале про летчиков :)

Gaen 03.12.2009 16:28

Цитата:

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

BlooDHounD 03.12.2009 17:14

wvxvw, не представляешь? так я же код написал ) событие срабатывает у всех синхронно согласно моему коду. есть глобальный диспатчер, который является статическим экземпляром ( _BROADCASTER ). при этом писать супер навороченный функционал по обработки ВСЕХ дисплэйобджектов не нужно. даже не нужно собирать их в коллекцию. достаточно подписать на событие у этого брадскасера и послать его от своего имени. в твоём же случаи надо написать тонну кода, который работает медленнее, так как он пробегает ВСЕХ детей и проверяет, а есть ли у них слушатели? в моей схеме в коллекции собираются только объекты, у которых есть слушатели. и собираются они готовым функционалом EventDispatcher'а, что с точки зрения здравого смысла и экономичнее и быстрее, а с точки зрения ООП, ваще идеально вписывается ( переиспользование инкапсулированного класса ).


твой пример с addChild мне опять не понятен. если ребёнку не нужно знать, что его добавили куда-то, то зачем в вообще заморачиваться с onAdded? и скорее всего не вызывается в плэйере такого метода. как мне кажется там вызывается метод
Код AS3:

internal function setParent(parent:DisplayObjectContainer):void;

, что опять же логичнее. ребёнок сравнивает "а тот ли у него папа?". если тот же, то return. если новый, то диспатч removed, сохранили папу, и следом сразу диспатч added. все довольны. если надо, то конечно мы сперва проверим подписчиков, но этот не тот случай, так как тут bubbling. внутри метода setParent, мы ещё сражу вызовем метод setStage, в котором произведём аналогичную операцию.

события диспатчатся от имени child, почему о них должен заботится родитель? не понятно. так же непонятно, зачем родителю совершать ненужные и идиотские проверки, если ребёнок не должен диспатчить это событие ни в коем случаи? в моей схеме понятно. отнаследовались и переопределили setParent. а в твоей? закидываем дрожжей в родительский класс и начинаем плодить switch/case на каждое особенное поведение ребёнка в одном методе?

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

резюме: повторяю в 3й раз, что то, что ты описываешь ни коем образом не касается имплементации EventDispatcher. это вопрос из области "а использовать ли мне ООП"?

wvxvw 03.12.2009 17:49

Blood, твой код не отражает действительность - таргет события полученого в обработчике ентерфрейма не будет == _BROADCASTER... я не спорю о достоинствах такой схемы, просто в реальности она так не работает.

Как раз если бы ты прочитал внимательнее, ты бы понял, что никакого switch-case не предвидится. Есть набор предопределенных событий которые может продиспатчить родитель. И тип ребенка не влияет на логику - главное, чтобы ребенок был IEventDispatcher.
По поводу:
Код AS3:

internal function setParent(parent:DisplayObjectContainer):void;

Как раз, опять же, если ты прочитаешь внимательнее, то увидишь, что мне как раз не нужно давать ссылку на родителя, ни явно ни в обход ни вообще никак, - мне нужно это избежать... Мне нужно передать событие сигналящее о том, что, например, нужно обновить внешний вид... Как пример - ситуация со стейдж - каждый кому не лень вдруг может сеттить displayMode / align? И по-твоему, это как бы хорошо и в порядке вещей?

BlooDHounD 03.12.2009 19:03

кароче. ты видишь то, что хочешь видеть и чёрти знает что придумываешь. да, target !== _BROADCASTER, так как именно это нам и надо! ты вот сейчас о чём? нам же надо что бы таргет был child.

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

Цитата:

Сообщение от wvxvw
Как раз если бы ты прочитал внимательнее, ты бы понял, что никакого switch-case не предвидится. Есть набор предопределенных событий которые может продиспатчить родитель. И тип ребенка не влияет на логику - главное, чтобы ребенок был IEventDispatcher.

я всё очень внимательно прочитал. может быть даже слишком внимательно, и поэтому ты не понимаешь теперь, что события тут не причём. ребёнок IEventDispatcher, значит есть метод dispatchEvent. а ты паришь мозги про детей не IEventDispatcher. у которых хочешь впихивать какие-то методы onAdded(), которых может и не быть. то есть к интерфейсу IEventDispatcher они отношения не имеют.
Цитата:

Сообщение от wvxvw
Мне нужно передать событие сигналящее о том, что, например, нужно обновить внешний вид...

во флэше это сделано как-то так:
Код AS3:

stage.invalidate();

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

Котяра 04.12.2009 12:36

вот как может выглядить код в базовом EventDispather
Код AS3:

public function addEventListener(evenType:String, listener:Function):void
{
if (evenType==Event.ENTER_FRAME)
globalEnterFrameDispatсher.addEventListener(Event.ENTER_FRAME,dispatchEnterFrameEvent);
//дальше обычный ф-ционал
}
public function dispatchEnterFrameEvent(event:Event){
// что-то вроде этого
event.currentTarget = this;
event.target = this;
// или просто создаем новый энтерфрэйм эвент
dispatchEvent(event));
}

В этом случае globalEnterFrameDispatсher рассылает события только тем объектам у которых есть слушатели.

BlooDHounD 05.12.2009 16:43

Котяра, чем Ваш код отличается от моего? не считая дополнительных телодвижений, и дополнительной функции?

Котяра 07.12.2009 10:17

Цитата:

Сообщение от BlooDHounD (Сообщение 870425)
Котяра, чем Ваш код отличается от моего? не считая дополнительных телодвижений, и дополнительной функции?

Каюсь.. ваш код я как-то пропустил мимо..
Если отличий мало, значит это что-то да значит)
а дополнительная ф-ция равна super.dispatchEvent в вашей реализации


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

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