|
|
|||||
Регистрация: Aug 2012
Сообщений: 108
|
Starling binding
Добрый вечер. Решил попытаться приобщиться на этом форуме к best practices. Ситуация следующая: автор Feathers на форуме сообщил, что сигналы теперь лучше не использовать поскольку события старлинга очень даже good. Я решил переписать для начала бинды флекса [Bindable]. Первоначальный вариант получился такой, что на каждую переменную пришлось делать гет-сет, которые раздули всю модель в несколько раз и из переменных + 3-4 функций в сумме около 100 строк (на всю модель) получилось строк 300. К тому же, сеттеры приходилось делать копипастой, что не слишком-то меня устроило. Решил сделать
Кусок модели-синглтона public class StateManager extends EventDispatcher private static var _instance: StateManager = new StateManager(); public static function get instance(): StateManager { return _instance; } public var _state: uint = STATE_LOADING; public function get state(): uint { return _state; } public function set state(value: uint): void { Bind.masterSetter(instance, "_state", value); } import starling.events.Event; import starling.events.EventDispatcher; public class Bind { public static const VARIABLE_CHANGE_ENDING: String = "_changed"; public function Bind() { if (Bind) throw new Error("Bind is abstract."); } public static function masterSetter(host: EventDispatcher, varName: String, value: Object): void { if (host[varName] == value) return; host[varName] = value; trace(varName, value); host.dispatchEvent(new Event(varName + VARIABLE_CHANGE_ENDING)); } public static function bindSetter(setter: Function, host: EventDispatcher, varName: String): void { host.addEventListener(varName + VARIABLE_CHANGE_ENDING, setter); } public static function bindProperty(site: Object, varName: String, host: EventDispatcher, chain: String): void { host.addEventListener(chain + VARIABLE_CHANGE_ENDING, bindChanged); function bindChanged(e: Event): void { site[varName] = host[chain]; } } } Известные проблемы: для использования функции masterSetter( Удобства: Ну вообщем-то вроде как толковая замена стандартному бинду флекса без всяких изысков на событиях старлинга, которые реально стоит использовать в противовес стандартным флэшовым событиям. Варианты: Может, попробовать сделать Bind не как класс, а как отдельные функции через include чтобы переменные были private? Либо есть вариант в каком-то фреймворке делать BindInt, BindString etc. Последний раз редактировалось Psijic; 08.03.2014 в 20:58. |
|
|||||
Регистрация: Aug 2012
Сообщений: 108
|
Цитата:
Так, выяснилось, что текущий masterSetter работает не совсем корректно. По-моему, событие не считывается при изменении. Можно попробовать добавлять на stage, тогда и наследоваться от dispatchEvent не придется, хотя по-моему, этот метод хуже. Хотя, с хорошими сепаратором и парсилкой можно и так заделать. Если вынести masterSetter как отдельную функцию, то переменные можно оставлять private. Вопрос с событиями. Добавлено через 5 минут |
|
|||||
блогер
Регистрация: Jun 2005
Адрес: Господи пожалуйста не Новосибирск
Сообщений: 6,598
Записей в блоге: 17
|
А если попробовать наследоваться, кажется, от Proxy и ловить undefined method?
Или сделать класс dynamic и метапрограммированием добавлять методы в рантайме?
__________________
Тут мужик танцует и поёт про флэш |
|
|||||
Регистрация: Aug 2012
Сообщений: 108
|
Цитата:
Оказалось, события все-таки передаются и считываются правильно. Значение не обновляется. this - похоже, не прокатывает. Показывает global Последний раз редактировалось Psijic; 10.03.2014 в 16:19. |
|
|||||
разу оговорюсь, что я мало понимаю в этом,
но если единственной задачей этой конструкции будет синхронизация свойств, то я не вижу почему бы по-простому не создать словарь соответствий и менять свойства напрямую, без посредников (событий) package { import flash.utils.describeType; import flash.utils.Dictionary; public class Bind { public static var map:Dictionary = new Dictionary(); public function Bind() { throw("Bind is static"); } public static function update(src:Object, prop:String):void { if (map[src] && map[src][prop]) { for each(var obj:Object in map[src][prop]) { obj.targ[obj.prop]= src[prop]; } } } public static function bindProperty(src: Object, srcProp: String, targ: Object, targProp: String): void { if (!map[src]) map[src] = {}; if (!map[src][srcProp]) map[src][srcProp] = []; map[src][srcProp].push( { targ:targ, prop:targProp } ); } } } package { import flash.display.Sprite; public class Main extends Sprite { public var prop:String; public function Main():void { var test:Test = new Test(); var test2:Object = { }; Bind.bindProperty(test, "prop", this, "prop"); Bind.bindProperty(test, "prop", test2, "prop"); test.prop = "newValue"; trace( "this.prop : " + this.prop ); trace( "test2.prop : " + test2.prop ); } } } |
|
|||||
блогер
Регистрация: Jun 2005
Адрес: Господи пожалуйста не Новосибирск
Сообщений: 6,598
Записей в блоге: 17
|
dynamic class SexyModel extends Proxy implements IEventDispatcher{ // todo: implement IEventDispatcher public function SexyModel() { } override flash_proxy function callProperty(methodName:*, ... args):* { // скажем, меняем свойство если обращаемся так: sexyModel.setCustomers(customers), sexyModel.setWaitFlag, т.е. метод начинается на 'set' // 1. проверяем подходит ли methodName под нашу маску (set*) // 2. меняем своё свойство. Например, если такого свойства у нас нет – лучше кинуть RTE или хотя бы warn самостоятельно, т.к. класс dynamic и VM за тебя это не сделает // т.к. язык типизированный, идиологически придётся сравнивать даже типы вручную. // 3. диспатчим правильный эвент } override flash_proxy function getProperty(name:*):* { // или вариант, что все свойства к модели будут обращаться через [], типа sexyModel[sexyProperty] = 'sexyValue' } override flash_proxy function setProperty(name:*, value:*):void { // см. выше } } 1) "свои" методы модели, возможно, придётся разруливать через тот же callProperty. Вероятно любое обращение к свойствам идёт через это callProperty, поэтому это накладывает свои ограничения, но они решаемы. Я точно не знаю, на as давненько не писал ничего серьезного. 2) Скорее всего это медленно. Чаще всего это не будет никого волновать, но для "узких" мест может потребоваться "настоящий" инлайн-код и прочий тектоник вокруг этой модели. Use wisely.
__________________
Тут мужик танцует и поёт про флэш |
|
|||||
Регистрация: Aug 2012
Сообщений: 108
|
silin
я так понял, у вас реализован Observer? Я сначала тоже думал сделать через сигналы, а потом нашел вот ту статью, что я упоминал в заголовке. Psycho Tiger на вид что-то слишком неочевидно. Цитата:
Добавлено через 33 минуты А можно как-нибудь подключить функцию без пакета? Пробовал вынести function masterSetter1(host: EventDispatcher, varName: String, value: Object): void { if (host[Bind.VARIABLE_PRIVATE_PREFIX + varName] == value) return; host[Bind.VARIABLE_PRIVATE_PREFIX + varName] = value; host[varName] = value; host.dispatchEvent(new Event(varName + Bind.VARIABLE_CHANGE_ENDING)); } но саму функцию не смог Последний раз редактировалось Psijic; 11.03.2014 в 14:16. |
|
|||||
>>у вас реализован Observer?..
ничего этого не понимаю, но городить систему событий со связыванием пар свойств через замыкание в анонимном листенере ну как-то очень уж затейливо на мой взгляд при том, что ничего не мешает сделать это напрямую событийная модель старлинга\физерса, как и предпочтения Tynjala, тоже не понятно при чем здесь |
|
|||||
Регистрация: Aug 2012
Сообщений: 108
|
Цитата:
P.S. Хорошая реализация Observera, прямо под имена функций биндинга. Надо бы заценить на тесте. Последний раз редактировалось Psijic; 11.03.2014 в 15:41. |
Часовой пояс GMT +4, время: 17:49. |
|
« Предыдущая тема | Следующая тема » |
Теги |
bind , Binding , MVC , Starling , связывание |
|
|