Под впечатлением от крайней конференции я сделал для себя массу выводов. Одним из которых и станет эта статья. Речь в статье пойдет о библиотеке bindx.
Но для начала или наоборот по прочтению статьи советую посмотреть мою презентацию на конференции об этой же библиотеке:
Data binding
Если снова обратиться к википедии, а именно к определению понятия Data binding, то мы сразу узнаем одну из основных задач, для чего биндинги могут быть использованны - связь GUI с моделью.
Вообще data binding можно и стоит переводить как связывание данных, а не называть заморским и не всегда понятным словом - биндинги. Из понятия “связывание данных” понятно, что мы связываем что-то, а связь подразумевает, что у нас есть как минимум два операнда, которых мы собственно и связываем. Но хватит ванговать, смотрим картинку:

Кто пошел по ссылке выше на msdn, тот скорее всего ее уже нашел. Видно что у нас есть источник и целевой объект, источних предоставляет нам данные, которые мы и передаем приемнику. Но в отличии от простой передачи свойсва, тут происходит именно связывание (поэтому двухстронняя стрелочка, хоть данные бегают лишь в одну сторону). Связывание данных позволяет целевому объекту быть всегда вкурсе о значении свойства и своевременное оповещает его об этом изменении.
На самом деле связований бывает несколько видов, не говоря уже о самих реализация, но все это можно узнать из просторов интернета. Теперь, когда мы хоть примерно знаем как должно работать связывание, подумаем, где бы мы могли это использовать в Haxe разработке. Но давайте рассмортим применение внимательнее, а уже потом вернемся к самой либе.
Применение
Чтобы не придумывать, я и AxGord лишь расскажем, где реально мы это используем: (а в дальшейшем надеюсь не только мы)
Привязка логики модели к визуальной части. Самое частое и простое вывод текста. Используется как для Unity так и для Flash платформы.
Все описанные выше примеры - это лишь малая часть, где можно использовать связывание данных. Но даже их, должно хватить, чтобы заинтересовать вас.
bindx (bindx.IBindable)
Вернемся к нашим баранам и рассмотрим основные возможности, которые предоставляет наша библиотека bindx.
Для начала вам надо знать, что все что вам надо - это интерфейс bindx.IBindable и утилитарный класс bindx.Bind, который чаще всего вы будете использовать через using bindx.Bind. Ну еще не стоит забывать про мета данные, которые помечают свойства для связывания.
Рассмотрим простой пример класса реализующего интерфейс IBindable
С первой же строчки мы видим мету @bindable перед определением класса, она не обязательная, но ее наличие говорит библиотеке, о том чтобы всем публичным переменным с сеттером default или set автоматически добавлялась мета @bindable. Это очень удобно и позволяет сильно сократить кол-во набираемых символов. В нашем примере переменная a получит мету @bindable, т.к. соответствует всем условиям.
Значит еще раз, @bindable перед классом автоматически добавит мету @bindable всем
Далее видно, что у свойства b заданные дополнительные параметры в мете. На сегодняшний день поддерживаются два дополнительных свойства:
force (по умолчанию false) - в случае true не смотрит на сеттер и никак его не меняет (об этом подробнее ниже). Force флаг очень нужен в случае когда сеттер указан как never, null или dynamicinlineSetter (по умолчанию true) - в случае генерации сеттера для свойства этот флаг отвечает, будет ли сеттер заинлайнен или нет.Теперь когда мы немного разобрались с мета данными, самое время разобраться, зачем же мы их так тщательно расставили. Дело в том, что все @bindable переменные или почти все, подвергаются сильным изменениям, а именно для default сеттера создается сеттер функция и переменные типа var a:Int; становятся переменными типа var a(default, set):Int, а в случае если сеттер уже существовал, то тело функции сеттера немного изменится. Сделано это все, для того, чтобы оповещать остальных, об изменениях @bindable свойств.
Рассмотрим отдельно два случая:
var a:Int;Inline метод будет если не указать дополнительный флаг inlineSetter = false.
var b(default, set):Int;тогда измененный сеттер с поддержкой связывания данных будет выглядеть так:
Первое, что бросается в глаза, это проверка с предыдущим значением, это необходимо, чтобы не было ложных срабатываний сеттера и в большинстве случаев никак не повредит вашему сеттеру, а даже напротив, позволяет вам не делать такую проверку самому (для остальных случаев, когда такая проверка только мешает есть флаг force (см. выше)). Ну и второе изменение сеттера, это диспатч изменения прямо перед самым ретурном. И не стоит боятся использовать сложные конструкции в ретурнах, типа return this.a = value; библиотека отлично обработает их, правда изменив на боле сложную конструкцию:
Это нужно знать и учитывать, особенно если у переменной a есть геттер и вам не хочется, чтобы он срабатывал несколько раз за один сеттер.
Теперь, когда вы точно знаете, что на самом деле сделает библиотека с @bindable свойствами, я могу спать спокойно. Ну т.е. пора переходить к загадочному __fieldsBindings__. На самом деле таких загадочных свойства у всех IBindable классов целых два. Они даже прямо прописанны в интерфейсе:
Но определять их в классах не обязательно, я бы даже рекомендовал никогда не делать этого, оставив и это грязное дело библиотеке. Все что надо от вас, то это обязательно определять конструктор во всех IBindable классах. Это нужно, чтобы встроить в него инициализаторы сигналов.
Но вернемся к нашим сигналам, __fieldBindings__ оповещают в случае, если хоть одно свойство изменилось, __methodBindings__ - в случае методов (про биндинг методов смотрите в моем видео). Но ни те ни другие в 99% случаев вам напрямую использовать не понадобится и я снова рекомендовал бы вам не трогать их никогда, разве что в деструкторе, в котором можно вызвать destroy() метод у обоих сигналов, чтобы наверняка отписаться от всех слушателей и позволить сборщику мусора сделать свое грязное дело с легкостью. Самые любознательные могут изучить код самих сигналов и может даже оптимизировать их, т.к. их скорость это самое узкое место библиотеки.
Уже тут у вас должно были сложиться вырожение лица аналогичное смайлу 0_o, по крайней мере именно к этому эффекту стремиться библиотека bindx. И вы просто не поверите, но впереди еще масса интересного. Интересного еще настолько много, что представить это в данной статье не вижу возможным. Поэтому на этом мы пока остановимся, но это остановка на полуслове и скоро будет продолжение. А пока небольшие выводы.
Вывод
В данной статье мы немного узнали о связывании данных, мы почти полностью узнали как работает макрос (а-а-а, я впервые за всю статью использовал это слово, а ведь на самом деле 90% работы делают в либе именно макросы), который автоматически вызывается в случае реализации bindx.IBindable интерфейса. Мы узнали некоторые важные обстоятельства поведения биндингов, которых нет даже в документации (а все потому что, документации тоже нет). Если вернуться к нашей первой картинке, то видно, что мы изучили то как bindx подготавливает источник привязки.
Что нам осталось? Осталось изучить как нам к этому источнику привязываться. Об этом в следующей статье.
P.S. Установить библиотеку можно и через haxelib:
Отдельная благодарность AxGord-у, SlavaRa, Харват Егору и Бурдун Александру за помощь в написании статьи.