Ре-факторинг Для паттерна MVC -Сомнения по поводу отделения вида от контроллера - PullRequest
6 голосов
/ 17 июля 2010

Я пытаюсь реорганизовать свое приложение (с 1000+ строками кода GUI) в шаблон стиля MVC.Логический код уже отделен от графического интерфейса, так что это не проблема.Меня беспокоит разделение вида с контроллера.Я понимаю основной принцип MVC и этот учебник в вики wxpython был очень полезен, но пример кода немного упрощен и оставляет у меня сомнения, когда я пытаюсь применить принципал к своему собственному проекту, которыйнемного сложнее.

Фрагмент структуры ..

У меня есть MainWindow с несколькими виджетами, включаяnoteBook (раздел с вкладками), блокнот имеет несколько вкладок, одна из вкладок (которую я называю FilterTab) содержит два экземпляра класса (который я называю FilterPanel), который представляет собой панель с listbox , три кнопки , одну для очистки, одну для удаления и одну для добавления элементов в / из списка.В зависимости от флагов, передаваемых классу при создании экземпляра, событие добавления кнопок может создавать различные типы диалогов, например, диалоговое окно ввода текста или directoryPicker и т. Д.обработчики похоронены в классе FilterPanel.

Если бы я преобразовал эту часть в MVC, мне пришлось бы привязать события кнопки для каждого экземпляра FilterPanel в моем контроллере (а не в классе filterPanel) - в этом случае их два (экземпляры filterPanel)

Таким образом, у меня было бы что-то подобное для каждой кнопки (3 кнопки на filterPanel * количество экземпляров панели) плюс обработчики.

 self.mainWindow.filterTab.dirFilterPnl.Bind(wx.EVT_BUTTON,
                                    self.onAdd_dirFilterPnl, 
                            self.mainWindow.filterTab.dirFilterPnl.addBtn,
                            self.mainWindow.filterTab.dirFilterPnl.addBtn.GetId()
                                    )

, что добавляет много дополнительного кода,(удвойте количество обработчиков событий, если у меня только два экземпляра filterPanel)

Итак, я хотел бы знать, правильно ли я выбрал подход?

Ответы [ 2 ]

9 голосов
/ 17 июля 2010

Если бы я преобразовал эту часть в MVC, мне пришлось бы привязать события кнопки для каждого экземпляра FilterPanel в моем контроллере (а не в классе filterPanel)

Необязательно!Философия и практика MVC не подразумевают, что «представления» являются элементарными виджетами;Ваш FilterPanel вполне может рассматриваться / реализовываться как «расширенный / составной» виджет, который генерирует свои собственные «события» более высокого уровня (направленные на контроллер) и обновляется соответствующим образом.Таким образом, этот составной виджет может иметь обработчики для «событий» более низкого уровня и синтезировать из них события более высокого уровня, отправляя их на контроллер;контроллеру не нужно знать или заботиться о каждой кнопке и т. д., только о событиях более высокой абстракции, которые он получает, таких как «пользователь хочет выбрать каталог для цели X» или «пользователь хочет ввести текст для цели Y»- и отвечайте на них, сообщая представлению, что делать.

Ключевым моментом является то, что представление не принимает "семантических" решений на основе событий, которые оно обрабатывает, и при этом оно никогда не отправляет какую-либо команду модели.- контроллер является незаменимым «посредником» для всех таких взаимодействий.

Для аналогии, учтите, что на самом нижнем уровне GUI есть события очень низкого уровня, такие как «левая кнопка мыши вниз» и «левая мышь»button up "-" виджет кнопки "реагирует непосредственно на них, изменяя внешний вид кнопки (« визуальное »решение, а не« стратегическое ») и в конечном итоге, если и когда это уместно, синтезирует событие с более высокой абстракцией, такое как«нажата кнопка «(когда за кнопкой мыши следует нажатие кнопки мыши без промежуточной мыши»движения, опровергающие гипотезу «щелчка», например).Последний затем направляется на то, что более высокому уровню необходимо «реагировать» на нажатия кнопок.

Аналогично, ваши расширенные / составные виджеты могут принимать такие события и синтезировать те из них с более высокой абстракцией, на которые контроллер реагирует.(Одно и то же абстрактное событие может быть сгенерировано нажатием кнопки, выбором меню, определенными нажатиями клавиш ... контроллер не заботится об этих «визуальных» соображениях нижнего уровня, это работа представления / виджета и представление / виджетне кодирует «стратегические» решения и действия для таких взаимодействий пользователей, это работа контроллера).

Разделение задач помогает в таких вопросах, как тестирование и гибкость приложений;не случайно, что такие преимущества можно купить по цене еще большего количества кода по сравнению с альтернативой, где все жестко закодировано ... но если вы выбираете MVC, вы подразумеваете, что цена для вас вполне оправдана.

wx может не быть идеальной средой для реализации этого, но вы можете подкласс wx.Event - или вы можете использовать отдельную систему событий, такую ​​как pydispatcher для событий с более высокой абстракцией, которые протекают между отдельными подсистемами, чтобы отделить контроллер от конкретного выбора структуры GUI.Я обычно использую Qt, чья модель сигналов / слотов, IMNSHO, расширяет / масштабирует лучше, чем системы событий типичных каркасов GUI.Но это другой выбор и другая проблема.

1 голос
/ 17 июля 2010

wxPython включает pubsub, который следует методике публикации / подписки. Это похоже на pydispatcher, хотя их реализации отличаются. В wxPython wiki есть несколько примеров использования pubsub в вашей программе, а также есть простое руководство по этой теме:

http://www.blog.pythonlibrary.org/2010/06/27/wxpython-and-pubsub-a-simple-tutorial/

MVC в графических интерфейсах не совсем то же самое, что и в Django или TurboGears. Я обнаружил, что могу поместить большую часть своей логики в контроллеры, и в своем «представлении» я просто привязываюсь к контроллеру. Как то так:

view.py

btn.Bind (wx.EVT_BUTTON, self.onButton)

def onButton (self, event): controller.someMethod (* args, ** kwargs)

В зависимости от вычисления, я могу запустить поток из моего контроллера и опубликовать результат позже, используя wx.CallAfter + pubsub.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...