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

Вернуться   Форум Flasher.ru > Flash > ActionScript 3.0

Версия для печати  Отправить по электронной почте    « Предыдущая тема | Следующая тема »  
Опции темы Опции просмотра
 
Создать новую тему Ответ
Старый 08.03.2014, 20:40
Psijic вне форума Посмотреть профиль Отправить личное сообщение для Psijic Найти все сообщения от Psijic
  № 1  
Ответить с цитированием
Psijic

Регистрация: Aug 2012
Сообщений: 108
Cool Starling binding

Добрый вечер. Решил попытаться приобщиться на этом форуме к best practices. Ситуация следующая: автор Feathers на форуме сообщил, что сигналы теперь лучше не использовать поскольку события старлинга очень даже good. Я решил переписать для начала бинды флекса [Bindable]. Первоначальный вариант получился такой, что на каждую переменную пришлось делать гет-сет, которые раздули всю модель в несколько раз и из переменных + 3-4 функций в сумме около 100 строк (на всю модель) получилось строк 300. К тому же, сеттеры приходилось делать копипастой, что не слишком-то меня устроило. Решил сделать подкаст подкласс. Оцените реализацию и посоветуйте best practices.

Кусок модели-синглтона
Код AS3:
public class StateManager extends EventDispatcher
 
        private static var _instance: StateManager = new StateManager();
 
        public static function get instance(): StateManager
        {
            return _instance;
        }
Код AS3:
        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);
        }
Сама бинд-утилита

Код AS3:
    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];
            }
 
        }
 
    }
Вызов ака во Flex
Код AS3:
Bind.bindSetter(stateChanged, StateManager.instance, "state");
Код AS3:
Bind.bindProperty(io, "dataProvider", model, dataProvider);
Известные проблемы:
для использования функции masterSetter(тм) пришлось делать переменные public. Думал, обойдется хотя бы internal, но не вышло. Хотя, в feathers автор рекомендует для разработчиков фреймворка не делать private - переменных чтобы можно было легче наследоваться от компонентов, все-таки у меня это вроде как главная проблема.

Удобства:
Ну вообщем-то вроде как толковая замена стандартному бинду флекса без всяких изысков на событиях старлинга, которые реально стоит использовать в противовес стандартным флэшовым событиям.

Варианты:
Может, попробовать сделать Bind не как класс, а как отдельные функции через include чтобы переменные были private? Либо есть вариант в каком-то фреймворке делать BindInt, BindString etc.


Последний раз редактировалось Psijic; 08.03.2014 в 20:58.
Старый 09.03.2014, 08:16
Hauts вне форума Посмотреть профиль Отправить личное сообщение для Hauts Посетить домашнюю страницу Hauts Найти все сообщения от Hauts
  № 2  
Ответить с цитированием
Hauts
 
Аватар для Hauts

блогер
Регистрация: Feb 2008
Адрес: Россия, Новосибирск, Академгородок
Сообщений: 2,109
Записей в блоге: 1
Отправить сообщение для Hauts с помощью ICQ Отправить сообщение для Hauts с помощью Skype™
Извините, что вмешиваюсь без конструктива, но объясните мне практическую ценность такого?
__________________
hauts.ru

Старый 09.03.2014, 23:48
Psijic вне форума Посмотреть профиль Отправить личное сообщение для Psijic Найти все сообщения от Psijic
  № 3  
Ответить с цитированием
Psijic

Регистрация: Aug 2012
Сообщений: 108
Цитата:
Сообщение от Hauts Посмотреть сообщение
Извините, что вмешиваюсь без конструктива, но объясните мне практическую ценность такого?
Связь в системе MVC между классами Viev, Model, Controller.

Так, выяснилось, что текущий masterSetter работает не совсем корректно. По-моему, событие не считывается при изменении. Можно попробовать добавлять на stage, тогда и наследоваться от dispatchEvent не придется, хотя по-моему, этот метод хуже. Хотя, с хорошими сепаратором и парсилкой можно и так заделать.
Если вынести masterSetter как отдельную функцию, то переменные можно оставлять private. Вопрос с событиями.

Добавлено через 5 минут
Код AS3:
    public function masterSetter(host: EventDispatcher, varName: String, value: Object): void
    {
        if (this[Bind.VARIABLE_PRIVATE_PREFIX + varName] == value)
            return;
 
        this[Bind.VARIABLE_PRIVATE_PREFIX + varName] = value;
        host.dispatchEvent(new Event(varName + Bind.VARIABLE_CHANGE_ENDING));
    }

Старый 10.03.2014, 14:59
Psycho Tiger вне форума Посмотреть профиль Отправить личное сообщение для Psycho Tiger Найти все сообщения от Psycho Tiger
  № 4  
Ответить с цитированием
Psycho Tiger
 
Аватар для Psycho Tiger

блогер
Регистрация: Jun 2005
Адрес: Новосибирск :D
Сообщений: 6,548
Записей в блоге: 17
А если попробовать наследоваться, кажется, от Proxy и ловить undefined method?
Или сделать класс dynamic и метапрограммированием добавлять методы в рантайме?

Старый 10.03.2014, 15:40
Psijic вне форума Посмотреть профиль Отправить личное сообщение для Psijic Найти все сообщения от Psijic
  № 5  
Ответить с цитированием
Psijic

Регистрация: Aug 2012
Сообщений: 108
Цитата:
Сообщение от Psycho Tiger Посмотреть сообщение
А если попробовать наследоваться, кажется, от Proxy и ловить undefined method?
Или сделать класс dynamic и метапрограммированием добавлять методы в рантайме?
хм, вроде не сталкивался с таким, нужны пояснения.

Оказалось, события все-таки передаются и считываются правильно. Значение не обновляется. this - похоже, не прокатывает. Показывает global


Последний раз редактировалось Psijic; 10.03.2014 в 16:19.
Старый 10.03.2014, 17:26
silin вне форума Посмотреть профиль Посетить домашнюю страницу silin Найти все сообщения от silin
  № 6  
Ответить с цитированием
silin
 
Аватар для silin

блогер
Регистрация: Mar 2003
Адрес: Моск. обл.
Сообщений: 5,269
Записей в блоге: 6
разу оговорюсь, что я мало понимаю в этом,
но если единственной задачей этой конструкции будет синхронизация свойств, то я не вижу почему бы по-простому не создать словарь соответствий и менять свойства напрямую, без посредников (событий)

Код AS3:
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 } );
 
		}
	}
 
}
Код AS3:
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 );
 
		}
 
	}
 
}
Код AS3:
package  
{
 
	public class Test 
	{
		private var _prop:String = "xx";
 
		public function Test() {}
 
		public function get prop():String 
		{
			return _prop;
		}
 
		public function set prop(value:String):void 
		{
			if (_prop != value)
			{
				_prop = value;
				Bind.update(this, "prop");
 
			}
 
		}
 
	}
 
}

Старый 11.03.2014, 10:41
Psycho Tiger вне форума Посмотреть профиль Отправить личное сообщение для Psycho Tiger Найти все сообщения от Psycho Tiger
  № 7  
Ответить с цитированием
Psycho Tiger
 
Аватар для Psycho Tiger

блогер
Регистрация: Jun 2005
Адрес: Новосибирск :D
Сообщений: 6,548
Записей в блоге: 17
Код AS3:
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.

Старый 11.03.2014, 13:42
Psijic вне форума Посмотреть профиль Отправить личное сообщение для Psijic Найти все сообщения от Psijic
  № 8  
Ответить с цитированием
Psijic

Регистрация: Aug 2012
Сообщений: 108
silin
я так понял, у вас реализован Observer? Я сначала тоже думал сделать через сигналы, а потом нашел вот ту статью, что я упоминал в заголовке.
Psycho Tiger
на вид что-то слишком неочевидно.

Цитата:
2) Скорее всего это медленно. Чаще всего это не будет никого волновать.
это все-таки важно )). Лучше уж тогда вручную прописывать каждый сеттер либо обсервер.

Добавлено через 33 минуты
А можно как-нибудь подключить функцию без пакета? Пробовал вынести

Код AS3:
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));
}
Даже подключил файл с ней
Код AS3:
include '../../../masterSetter.as';
но саму функцию не смог


Последний раз редактировалось Psijic; 11.03.2014 в 14:16.
Старый 11.03.2014, 15:01
silin вне форума Посмотреть профиль Посетить домашнюю страницу silin Найти все сообщения от silin
  № 9  
Ответить с цитированием
silin
 
Аватар для silin

блогер
Регистрация: Mar 2003
Адрес: Моск. обл.
Сообщений: 5,269
Записей в блоге: 6
>>у вас реализован Observer?..
ничего этого не понимаю, но городить систему событий со связыванием пар свойств через замыкание в анонимном листенере ну как-то очень уж затейливо на мой взгляд при том, что ничего не мешает сделать это напрямую
событийная модель старлинга\физерса, как и предпочтения Tynjala, тоже не понятно при чем здесь

Старый 11.03.2014, 15:24
Psijic вне форума Посмотреть профиль Отправить личное сообщение для Psijic Найти все сообщения от Psijic
  № 10  
Ответить с цитированием
Psijic

Регистрация: Aug 2012
Сообщений: 108
Цитата:
Сообщение от silin Посмотреть сообщение
>>у вас реализован Observer?..
ничего этого не понимаю, но городить систему событий со связыванием пар свойств через замыкание в анонимном листенере ну как-то очень уж затейливо на мой взгляд при том, что ничего не мешает сделать это напрямую
событийная модель старлинга\физерса, как и предпочтения Tynjala, тоже не понятно при чем здесь
Думаю, это из-за того что иногда надо послать событие контейнеру, например, из 20 кнопок, а не каждой кнопке в отдельности, а потом вверх по цепочке. Хотя, через обсервер тоже можно, в принципе, сделать. Вообщем, да, наверно, вопрос практики больше. В моих биндах тоже связь линейная.

P.S. Хорошая реализация Observera, прямо под имена функций биндинга. Надо бы заценить на тесте.


Последний раз редактировалось Psijic; 11.03.2014 в 15:41.
Создать новую тему Ответ Часовой пояс GMT +4, время: 22:46.
Быстрый переход
  « Предыдущая тема | Следующая тема »  

Теги
bind , Binding , MVC , Starling , связывание
Опции темы
Опции просмотра

Ваши права в разделе
Вы не можете создавать новые темы
Вы не можете отвечать в темах
Вы не можете прикреплять вложения
Вы не можете редактировать свои сообщения

BB коды Вкл.
Смайлы Вкл.
[IMG] код Вкл.
HTML код Выкл.


 


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


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