PDA

Просмотр полной версии : Дурное влияние Bindable на геттеры и сеттеры


__i
09.08.2007, 17:39
И так начнем наш рассказ

Жили были два класса:
Класс В (в потому что биндабл)

package
{
import flash.events.IEventDispatcher;
import flash.events.EventDispatcher;
[Bindable]
public class ItemVOB
{
private var _label : String;

public function set label( value:String ) : void
{
trace("I'm setter B");
_label = value;
}

public function get label( ) : String
{
return _label;
}
}
}

и класс А (потому что мне так захотелось)

package
{
import flash.events.IEventDispatcher;
import flash.events.EventDispatcher;

public class ItemVOA
{
private var _label : String;

public function set label( value:String ) : void
{
trace("I'm setter A");
_label = value;
}

public function get label( ) : String
{
return _label;
}
}
}


И отличались они только одним словом. Все бы ничего, жили бы они долго и счастливо есть бы не решил я сделать такой ход конем

var ia : ItemVOA = new ItemVOA();

ia.label = 'hod konem';
....
ia.label = 'hod konem';

var ib : ItemVOB = new ItemVOB();

ib.label = 'hod konem';
....
ib.label = 'hod konem';


И тут госпада делаем ставки какой результат работы вы увидите?

I'm setter A
I'm setter A
I'm setter B
I'm setter B

а вот вам и болт результат будет

I'm setter A
I'm setter A
I'm setter B


теперь приблизительное объясние болта (вероятно не вразумительное и может содержать кучу арфагарфических и лагических ошибок )

Мета тег [Bindable] говорит компилятору что он должен создать обертку для свойства указаного под биндабл (если смотреть в дебагере то в классе с такой переменной коявляються такие интересные приватные сеттеры типа _13234234label, которые туда не клали). Эта обертка является тем же геттером/сеттером которая при получении какого либо значения диспатчит событие об изменении данных, ну и заодно в эту обертку вставили проверку на изменение данных, т.е. в приведенном случае 'hod konem' == 'hod konem' - фактически данные не изменились, поээтому, реальный сеттер просто не вызывается!


Применение на практике :

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

Следите за кодом и ходом вышей мысли, будте счастливы!

Entropy
09.09.2007, 15:59
...и RTFM перед программингом.

The Flex compiler automatically generates an event named propertyChange for the property. If the property value remains the same on a write, Flex does not dispatch the event or update the property. To determine if the property value changes, Flex calls the getter method to obtain the current value of the property.

etc
09.09.2007, 16:04
Собственно, а зачем обновлять значение, если старое совпадает с текущим?
В сеттерах лучше всегда писать так:

private var _property:uint;

public function set property(value:uint):void {
if (value == this._property) {
return;
}

bla-bla-bla
}

miramax
10.09.2007, 00:40
Собственно, а зачем обновлять значение, если старое совпадает с текущим?Если в сеттер передаётся примитив, то незачем.
А если я не юзал коллекций, и у меня из старого кода передаётся массив?
А в сеттере ведётся перебор и апдейт элементов.
То сеттер не будет вызван, т.к. предыдущий массив прежний объект, хоть и с иной структурой.

etc
10.09.2007, 02:15
Надо просто поставить тест. Хотя не думаю, что оно не будет работать для непримитивов.

lowka
10.09.2007, 03:02
Если в сеттер передаётся примитив, то незачем.
А когда оказывается, что одно и тоже значение может на многое повлиять, то мы каждый раз обнуляем примитив перед очередным обновлением :)

__i
11.09.2007, 01:42
...и RTFM перед программингом.
ты каждый день перечитываешь о том, что земля круглая?

во вторых твоя цитата не из той оперы :D , но рядом, почти попал )

Entropy
19.09.2007, 09:41
Если в сеттер передаётся примитив, то незачем.
А если я не юзал коллекций, и у меня из старого кода передаётся массив?
А в сеттере ведётся перебор и апдейт элементов.
То сеттер не будет вызван, т.к. предыдущий массив прежний объект, хоть и с иной структурой.
Да, и это правильно, ибо data binding, по сути, шаблон Observer, где есть наблюдаемый объект и наблюдатель. Массив - наблюдаемый объект, и раз он не посылает сообщений наблюателю, то как последний узнает, что массив был изменен? А если массив содержит сложные объекты, свойства которых меняются, как узнать, что свойство элемента массива изменено? Есть только два способа - либо постоянно перебирать всю коллекцию и сравнивать ее состояние с неким ранее запомненым состоянием. Этот способ - шаблон Unit of work - в данном случае не применим из-за низкой производительности, либо самостоятельно посылать сообщения наблюдателю.

Атрибут Bindable - для тех лентяев, кто не хочет сам возиться с диспетчем сообщений - он это делает за вас. И механизм этого хорошо описан в документации, так что никаких проблем не вижу, все правильно сделано.