Форум: "Потрепаться";
Текущий архив: 2005.01.23;
Скачать: [xml.tar.bz2];
ВнизОбособление интерфейсной части в программе. Способы. Найти похожие ветки
← →
Aldor_ (2005-01-03 20:38) [0]Имеем чисто интерфейсный модуль, который о решаемой задаче мало что "знает". Например, в нем описана форма с функциями Get<Value> (считать то, что ввел юзер в поля) и Set<Value> (вывести что-то там-то и так-то). При этом интерфейсный модуль имеет доступ к engine-модулю, процедуры которого вызывает (например, DoJob :).
Engine-модуль тоже "поставляет" информацию интерфейсному модулю (например о том, какие возможности для выбора юзер должен иметь, чтобы интерфейс эти возможности должным образом обеспечил). Также engine-модуль, как уже было сказано, вызывает процедуры из интерфейсного модуля.
Отсюда проблема: оба модуля "видят" друг друга, не удается обеспечить какое-либо однообразие в том, "кто кого должен вызывать". Нет закономерности, по которой человек, читающий код будет знать, то ли engine-модуль берет значение из интерфейса через Form.GetValue, то ли интерфейс вызывает процедуру engine-модуля SetValue.
А отсюда вопрос: как вы обеспечиваете независимость интерфейса и задачи?
← →
Alex Konshin © (2005-01-03 21:24) [1]Обычно в таких ситуациях разделение естественно.
Тот "engine"-модуль не должен имет зависимости от интерфейсного модуля. Если же обработка некого события в engine требует выполнения каких-то действий в интерфейсе (перерисовки?), то эти действия должны быть в методах интерфейсного модуля, а вызываться они будут как обработчики событий. То есть, например, в engine описываешь событие OnЧто-тоChanged с нужными параметрами и вставляешь вызов его обработчика в нужных местах. Интерфейсный модуль просто вышает свои обработчики.
Этот прием позволяет избежать зависимостей во многих ситуациях взаимодействия какого-то объекта и формы. Если же развязать их все-таки не удается (что странно), то можно использовать второй прием - описание абстрактных классов или интерфейсов в третьем модуле и включение его в uses обоих модулей.
← →
Alex Konshin © (2005-01-03 21:33) [2]Да, кстати, иногда приходится передавать события через windows-сообщения. Особенно если они ассинхронные.
Полезно еще ввести блокировку обновления интерфейса (обычно достаточно счеткика и try-finally), чтобы избежать рекурсивных событий. Например, мы можем обновить состояние некого контрола, и это действие может спровоцировать другое событие.
← →
Vaitek © (2005-01-03 22:11) [3]Во-во, знакомая ситуация, об этом надо заранее думать, а то такие замысловатые вечные циклы получаюстся, через 4 события...
← →
Aldor_ (2005-01-03 22:40) [4]> Alex Konshin ©
Спасибо, объяснение классное. Пара вопросов:
передавать события через windows-сообщения
?? А как можно передать сообщение в engine-модуль, если не создавать доп. поток? Или может мне просто выспаться недо? %)
Полезно еще ввести блокировку обновления интерфейса (обычно достаточно счеткика и try-finally)
Так ведь для этого нужно, чтобы engine имел доступ к интерфейсу. Или опять дело в высыпании? И причем тут счетчик?
← →
Alex Konshin © (2005-01-03 23:09) [5]передавать события через windows-сообщения
?? А как можно передать сообщение в engine-модуль, если не создавать доп. поток? Или может мне просто выспаться недо? %)
А зачем engine получать сообщения? Интерфейс может спокойно вызывать его методы. Интерфейс зависит от engine, но не наоборот.
Хотя, если твой engine вертится в отдельном потоке, то может там и придется делать какие-то ухищрения, но для интерфейса все должно быть пофиг - engine должен выглядеть как черный ящик, у которого наружу торчат только методы и eventы. Вместо delphi eventов может быть какой-то иной callback механизм. Как там устроено внутри - личное дело того самого engine.
Полезно еще ввести блокировку обновления интерфейса (обычно достаточно счеткика и try-finally)
Так ведь для этого нужно, чтобы engine имел доступ к интерфейсу. Или опять дело в высыпании? И причем тут счетчик?
if LocCounter>0 then DeferChanges;
Inc(LockCounter);
try
DoChanges;
finally
Dec(LocCounter);
end;
Понятно, что в каждом случае вместо DeferChanged и DoChanges будут разные действия. В вырожденной ситуации DeferChanges может, например, быть пустой, т.е. изменения просто игнорируются. Тут же, как раз-таки для реализации DeferChanges может быть полезны windows сообщения: просто кидаем свое сообщение себе же, а в обработчике будет все тот же try-finaly и DoChanges. Хитрость тут в том, что мы откладываем обработку каких-то событий, чтобы не породить рекурсию вызовов. Правда, можно нарваться на рекурсию посылки сообщений, но вот тут и помогут счетчики вложенности.
Это все может быть тяжело для понимания, но советую все-таки разобраться. Универсального решения все равно нет, но имея в арсенале несколько таких приемов можно выкрутится из любой такой путаницы. Рекомендую посмотреть, как работают DoLayout,DeferLayout,InvalidateLayout и т.п. в реализации гридов.
Там по сути все эти способы используются.
← →
Alex Konshin © (2005-01-03 23:16) [6]Да, уж... столько опечаток...
if LockCounter>0 then DeferChanges
else
begin
Inc(LockCounter);
try
DoChanges;
finally
Dec(LockCounter);
CommitChanges; // ??? optional
end;
end;
Понятно, это всего лишь общая схема.
← →
iZEN © (2005-01-04 20:10) [7]Я такую ситуацию разруливаю следующим образом:
1) Объявляю интерфейс View с методом refresh(Object source) - модуль 1;
2) Имплементирую View в Form - модуль 2;
3) Создаю DataModel, которая "знает" только о View и ни о чём больше не догадывается (метод setView(View view)) - модуль 3;
4) Создаю Controller, который имеет представление о Form, DataModel и событиях, которые могут происходить в системе (например, ему известно, что пользователь нажал на Form) - модуль 4;
5) Пишу в Controller процедуру инстанцирования экземпляров DataModel, Form, назначаю для DataModel конкретную форму (dataModel.setView(form)), описываю ответные реакции на действия пользователя в форме, собираю всё вместе и фсё.
Приблизительно так:
http://izen.dev.juga.ru/notebook/prototypes/j2me/midp1/secondmidlet.html
Страницы: 1 вся ветка
Форум: "Потрепаться";
Текущий архив: 2005.01.23;
Скачать: [xml.tar.bz2];
Память: 0.48 MB
Время: 0.04 c