Я рад, что этот вопрос был задан, потому что GWT отчаянно нужен рельсовый способ структурирования приложения. Простой подход, основанный на передовом опыте, который будет работать для 90% всех вариантов использования и обеспечивает очень простую тестируемость.
В последние годы я использовал свою собственную реализацию MVP с очень пассивным представлением, которое порабощает себя всем, что велит ему докладчик.
Мое решение состояло в следующем:
- интерфейс для виджета, определяющий методы управления визуальным оформлением
- реализующий класс, который может быть Composite или использовать внешнюю библиотеку виджетов
- центральный Presenter для экрана, на котором размещено N представлений, состоящих из M виджетов
- центральная модель на экран, которая содержит данные, связанные с текущим визуальным оформлением
- универсальные классы слушателей, такие как "SourcesAddEvents [CustomerDTO]" (редактору здесь не нравятся реальные символы для обобщений java, поэтому я использовал квадратные скобки), потому что в противном случае у вас будет много одинаковых интерфейсов, которые отличаются только типом
Представления получают ссылку на докладчика в качестве параметра конструктора, поэтому они могут инициализировать свои события с докладчиком. Докладчик будет обрабатывать эти события и уведомлять другие виджеты / представления и / или вызывать gwt-rpc, который в случае успеха помещает свой результат в модель. Модель имеет типичный механизм прослушивания изменения свойства «Property [List [String]] names = ....», который зарегистрирован докладчиком, так что обновление модели по запросу gwt-rpc распространяется на все представления / виджеты, которые заинтересованы.
С этим appraoch я получил очень легкую тестируемость с EasyMock для моих AsynInterfaces. Я также получил возможность легко обмениваться реализацией представления / виджета, потому что все, что мне нужно было переписать, это код, который уведомлял докладчика о каком-либо событии - независимо от базового виджета (кнопки, ссылки и т. Д.).
Проблемы с моим подходом:
- Моя текущая реализация затрудняет синхронизацию значений данных между центральными моделями разных экранов. Скажем, у вас есть экран с набором категорий и другой экран, позволяющий добавлять / редактировать эти элементы. В настоящее время очень трудно распространять эти события изменения по границам экранов, потому что значения кэшируются в этих моделях, и трудно определить, являются ли некоторые вещи грязными (было бы легко в традиционном web1.0-html сценарий типа «тупой терминал» с декларативным кэшированием на стороне сервера.
- Параметры конструктора представлений обеспечивают супер-простое тестирование, но без солидной структуры Dependency-Injection, внутри "onModuleLoad ()" будет некоторый UGLY код фабрики / настройки. В то время, когда я начал это, я не знал о GIN Google, поэтому, когда я произвожу рефакторинг своего приложения, я буду использовать это, чтобы избавиться от этого шаблона. Интересным примером здесь является игра «HigherLower» внутри GIN-Trunk.
- В первый раз я неправильно понял историю, поэтому сложно перемещаться из одной части моего приложения в другую. Мой подход не знает истории, которая является серьезным спадом.
Мои решения этих проблем:
- Используйте GIN для удаления шаблона настройки, который трудно обслуживать
- При переходе от Gwt-Ext к GXT используйте его инфраструктуру MVC в качестве EventBus для подключения / отсоединения модульных экранов, чтобы избежать проблем с кэшированием / синхронизацией
- Подумайте о какой-то абстракции "Place", как Рэй Райан описал в своем выступлении на I / O 09, которая устраняет разрыв между событиями между GXT-MVC и GWTs-Hitory
- Использование MVP для виджетов для изоляции доступа к данным
Резюме:
Я не думаю, что можно использовать единый подход "MVP" для всего приложения. Однозначно нужна история для навигации по приложениям, шина событий, такая как GXT-MVC, для подключения / отключения экранов, и MVP, позволяющая легко тестировать доступ к данным для виджетов.
Поэтому я предлагаю многоуровневый подход, который объединяет эти три элемента, так как я считаю, что решение "one-event-mvp-system" не сработает. Навигация / Прикрепление экрана / Доступ к данным - это три разные задачи, и в последующие месяцы я проведу рефакторинг своего приложения (переход на GXT), чтобы использовать все три структуры событий для каждой проблемы отдельно (лучший инструмент для работы). Все три элемента не должны быть осведомлены друг о друге. Я знаю, что мое решение применимо только к GXT-проектам.
При написании больших приложений GWT я чувствую, что мне нужно заново изобрести что-то вроде Spring-MVC на клиенте, что действительно отстой, потому что требуется много времени и умственных способностей, чтобы выплюнуть что-то элегантное, как Spring MVC. GWT нуждается в каркасе приложений гораздо больше, чем в тех крошечных JS-оптимизациях, над которыми ребята-компиляторы так усердно работают.