Pull to refresh

Comments 18

Delphi XE2 и механизм livebindings для этой задачи пробовали использовать?
Пробовал. Тихий УЖАС. Текущая реализация LiveBindings не выдерживает никакой критики.
Такое впечатление, что эту технолгию клепали впопыхах, чтобы успеть реализовать гриды в FireMonkey (в FireMonkey они полностью отказались от классического data-aware, перейдя на объекты и списки объектов). Ну и плюс сюда еще проблема, что связи в LiveBindings задаются текстом (т.е. имена связываемых полей объектов нужно указать в виде строковых констант, соответственно прощай проверки через компиляцию и рефакторинг).
Есть мысли почему они отказались от старого доброго TDataSource? Я до сих пор не могу понять, что мешало оставить и то, и развивать новое?
Могу предположить, они могли отказаться от TDataSource по следующим причинам:
1) Двузвенные системы — это прошлый век. Разруливать конкурентный доступ и права на уровне СУБД — довольно сложное и неприятное занятие. Разруливать права доступа на клиенте — это, сами понимаете, не безопасно.
2) Data-aware компоненты очень плохо увязываются с объектно-ориентированным подходом к построению приложений. Да, это RAD (в смысле способ быстрой разработки приложений), но для серьезных проектов data-aware — это яма, которая становится тем глубже, чем бОльшим функционалом обладает приложение.

В целом, идея «зашить» в среду разработки средства для связи GUI с объектами довольно здравая. Но вот от получившейся у Embarcadero реализации у меня волосы дыбом. Возможно, они что-то поменяют в следующей версии Delphi, но пока я бы не стал рекомендовать использовать LiveBindings кому-либо.
Я бы добавил, что bind вручную надо оповещать об изменении свойств объекта — что, в принципе, делает LiveBindings просто бесполезным — разницы между поцедурами типа UpdateBackgroundTextEditColor основанными на значении эдита и live bindings правктически нет — и то и другое приходится вызывать по OnChange. Точнее одна все таки есть — перерисовка элементов интерфейса вручную хотя бы легко читается в коде.
Не туда написал. Это ответ на этот комментарий.
Ага, и это тоже. Плюс связывание нужно проводить в обе стороны — от объекта к GUI-контролу и обратно — от контрола к объекту. И так для каждого поля, а полей этих…
Ну не жесть ли это?
var
    ObjToControlStrValBind: TBindingExpression;
    ControlToObjStrValBind: TBindingExpression;
begin
  ObjToControlStrValBind := TBindings.CreateManagedBinding(
    { inputs }
    [TBindings.CreateAssociationScope([
      Associate(MyObject1, 'o')
      ])],
    'o.StrValue',
    { outputs }
    [TBindings.CreateAssociationScope([
      Associate(edStrValue, 'res')
      ])],
    'res.Text',
    nil);
end;
  ControlToObjStrValBind := TBindings.CreateManagedBinding(
    { inputs }
    [TBindings.CreateAssociationScope([
      Associate(edStrValue, 'res')
      ])],
    'res.Text',
    { outputs }
    [TBindings.CreateAssociationScope([
      Associate(MyObject1, 'o')
      ])],
      'o.StrValue',
    nil);



И как и написал GSirr, нужно не забывать дергать TBindings.Notify(Self, '') в setter'ах. Прям-таки скажу не айс…

Слоты и сигналы на коленке? :) Скажите, не рассматривали возможность создания Mediator'а для привязки экземпляра TUser к экземпляру формы? Тогда события форма не будет влиять непосредственно на юзера, плюс «отвязку» можно безопасно выполнить при наступлении OnDestroy любого из них. Кроме того, время жизни привязки будет зависеть от времени жизни медиатора, что иногда очень-очень удобно.
LiveBindings является отличным примером — over-engineered solution (по-русски что-то типа «избыточно спроектировнанное решение»). Это когда в систему заложили слишком много архитектуры и она начала затмевать собой исходную цель, ради которой это проектирование затевалось.

>Скажите, не рассматривали возможность создания Mediator'а для привязки экземпляра TUser к экземпляру формы?
Эти мысли крутятся в голове, но я так не делал. Основная проблема, как мне кажется, находится примерно в той же степи, что и LiveBindings. Если мы хотим связывать «что угодно с чем угодно», то нам придется как минимум достукиваться до полей объекта через RTTI, а не через нормальные обращения к его полям, т.к. если обращаться к конкретным полям, то на каждую пару «класс -> GUI-представление объектов этого класса (форма)» нужно заводить свой Mediator (т.к. поля у классов разные и формы тоже разные), а в этом я большого смысла не вижу, разве что кода будет побольше.

Но с архитектурной точки зрения ваше предложение выглядит здраво и в нем _теоретически_ костылей должно быть меньше, чем в моих упрощенных примерах. У вас есть пример подобного связывания или это пока просто идея?
В данный момент как раз занимаюсь подобной переработкой существующего ПО. В качестве контейнеров с данными используются наследники TDataSet. К каждому набору данных пишется фасад — объект с методами, изменяющими содержимое контейнера. Фасады я использую в коде для реализации бизнес-логики, к ним же пишу биндинги для вызова из скриптов.

Медиаторы в моем случае выполняют роль посредников между TDataSet и визуальным компонентом (в данный момент используется библиотека DevExpress). Кроме того, медиаторы устанавливают, что будет происходить при изменении данных, используя события объектов TField из набора данных. Ну и главное — медиаторы определяют внешний вид и поведение данных на основе ролей пользователей.

Я не имею права привести здесь реальный код, но если Вам интересно, то могу переработать его для примера. И еще деталь, я пишу на C++ и почти не знаю Object Pascal :)
Народ продолжает меня умилять негативной реакцией на Delphi, хотя в статье рассматривается проблема довольно общего характера :)
религиозный фанатизм =)
Delphi не любят в основном из-за отсутствия такого подхода, какой описан в Вашем цикле статей. Бизнес, гуи и SQL-запросы в одном обработчике нажатия кнопки на форме не редкость, увы.
В целом, конечно, замечательно что вас интересует тема «красивого кода», но есть вопрос ;)
Почему вы написали в топике MVC, а код по сути — шаблон наблюдатель? ;)
Observer на Delphi
в общем, предложение — убрать из названия mvc и пусть будет «почти Observer» ;)

про mvc классический — MVC
если хочется поизвращатся — вот моя альтернативная реализация MVC на Frame'ах в Delphi — при работе с базами и «rich gui» в ней есть свои плюсы.
Посмотрел ваш пример :). И хоть я и не люблю data-aware компоненты, сама идея мне понравилась — я такого еще не видел, легковесно и в то же время масштабируемо (для простых ситуаций). Правда в приведенном примере (как я понял из кода) никакой бизнес-логики, только отображение.

>>Почему вы написали в топике MVC, а код по сути — шаблон наблюдатель? ;)
Во-первых, MVC для меня скорее идеология, чем какая-то конкретная реализация. Один из способов реализации подхода, похожего на MVC (чтобы изменение GUI влияло на модель, а изменение модели по событию нотифицировало бы GUI о необходимости обновления) — это использование шаблона «Наблюдатель», что и было показано в статье.
Во-вторых, в своем примере вы активно используете data-aware компоненты. Data-aware компоненты — это примерно то же самое, о чем я писал в статье :). Там тоже есть модель (DataSet), есть представление (грид, DBEdit или что-то еще) и есть некая сущность, которая связывает модель и представление (DataSource). Вы думаете, что эта троица (DataSet + DataSource + гриды) не использует шаблон «Наблюдатель»? :) Если вы стоите уровнем выше, это еще не значит, что уровнем ниже происходит какая-то магия ;)
Ну, то что заглянули в пример говорит о многом ;) потому что, обычно, «диванные теоретики» этого не осиливают ;) в примере только шаблон — да, кода там практически нет, но это же пример… и основные сущности из статьи там на месте… если найдете время накидать в таком стиле несколько сущностей своего проекта — готов поучаствовать в обсуждении… или можно дополнить пример…

>>Один из способов реализации подхода, похожего на MVC
>>это использование шаблона «Наблюдатель»,
не зочу показатся занудой, но это все же разные вещи ;) MVC — прежде всего — архитектурный паттерн, котрой обещает свои плюшки, если вы следуете его идеалогии, а Observer — это более локальное решение другой проблемы. Вот, например, DataSource, действительно в тихую реализует Observer. Но причем тут MVC? ;) В реальном проекте может быть и то и то, но зачем подменять понятия? :)
Поддерживаю о продлении дискуссии и добавлении примеров из реальных проектов. Тема весьма интересна и обширна.
В книге Фриманов «Паттерны проектирования» (это такая адаптация GoF в стиле «для чайников») описано применение шаблона MVC в десктопных и веб-приложениях и сделан четкий вывод о том, что «MVC — это составной паттерн, состоящий из паттернов Наблюдатель, Стратегия и Компоновщик». Наблюдатель — для получения представлением уведомлений об изменении модели, Стратегия — для реализации разного поведения в контроллерах и Компоновщик — для отображения иерархического GUI. ИМХО, Компоновщик притянут за уши, но Наблюдатель и Стратегия в MVC точно присутствуют. Так что не надо ставить MVC в один ряд с примитивными паттернами, это составной паттерн (паттерн более высокого уровня).
Only those users with full accounts are able to leave comments. Log in, please.