Главная страница
Top.Mail.Ru    Яндекс.Метрика
Текущий архив: 2005.01.23;
Скачать: CL | DM;

Вниз

Обособление интерфейсной части в программе. Способы.   Найти похожие ветки 

 
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;
Скачать: CL | DM;

Наверх




Память: 0.5 MB
Время: 0.029 c
3-1102934638
Levitch
2004-12-13 13:43
2005.01.23
Руссификация базы данных


4-1102158229
aleman
2004-12-04 14:03
2005.01.23
Отлов без хук


6-1099510680
sloneniatko
2004-11-03 22:38
2005.01.23
Связь через COM


9-1097124544
Megabyte-ceercop
2004-10-07 08:49
2005.01.23
Карта с нелинейными тайлами.


1-1105521614
Zhekson
2005-01-12 12:20
2005.01.23
Навигация по StringGrid_у