В рамках развития информационной системы управления салоном красоты «МойСалон», уже около 10 лет успешно существующей и внедренной в десятки салонов России, его автором была выдвинута идея создания web-версии программы на базе одного из AJAX-фреймворков. Преследуя исследовательские и познавательные интересы, я занялся созданием макета и для начала разработал приблизительный проект прототипа, максимально независимый от конкретной библиотеки. В качестве двух возможных библиотек были выбраны Vaadin и SmartGWT. Развитие прототипа продолжилось с последней, поскольку именно она обеспечивает наибольшее кеширование страниц на стороне пользователя, максимально разгружая сервер от частых запросов.
Ядром исходной информационной системы является приложение на C++/MFC. Начальной задачей прототипирования было выбрано создание аналога журнала клиентов, одного из нескольких доступных пользователю журналов. Интерфейс журнала клиентов представлен ниже:
Очевидно, что основной элемент интерфейса – это список клиентов, который можно редактировать, а наиболее сложный элемент – это множество форм, доступных через различные закладки. Стоит отметить, что остальные журналы в той или иной степени следуют этому шаблону интерфейса.
В основу разработки был положен шаблон MVP «Model-View-Presenter», представляющий собой усовершенствованный вариант Model-View-Controller, в котором Model избавлена от функций хранения состояния интерфейса, а также может не участвовать в качестве обязательного посредника View-Controller(Presenter).
Создание объектов Model, View, Presenter было основано на шаблонах Factory Method и Abstract Factory, как показано на диаграммах ниже.
Иерархия классов для View (JournalAppGWT и EmployeeJournalApp – начальные классы для SmartGWT и Vaadin, соответственно):
Аналогичный подход использовался для создания объекта-модели. Инициализация модели, представления и объекта Presenter в коде GWT выглядит так:
//Создать подходящую модель
IModelFactory modelFactory = AbstractModelFactory.createModelFactory(AppTypes.getCurrentImpl());
IModel model = modelFactory.createModel(AppTypes.getCurrentType());
//Создать главное View
IViewFactory viewFactory = AbstractViewFactory.createViewFactory(AppTypes.getCurrentImpl());
IJournalView mainView = viewFactory.createMainView(AppTypes.getCurrentType(), model);
//Создать главный Presenter
JournalAppPresenter journalPresenter = new JournalAppPresenter(mainView, model);
//Поместить интерфейс на страницу
RootPanel.get("journalContainer").add((Widget)mainView.asWidget());
В данном коде учитывается разделение объектов по типу журнала (AppTypes.getCurrentType()) и по типу реализации интерфейса, то есть используемой AJAX-библиотеки (AppTypes.getCurrentImpl()). Конкретные объекты модели и представления размещены в соответствующих пакетах, например (SG = Smart Gwt):
com.mysaloon.ui.smartgwt.client.model.EmployeeModelSG
com.mysaloon.ui.smartgwt.client.view.EmployeeJournalViewSG
Абстрактные интерфейсы для model и view:
com.mysaloon.ui.core.view.IJournalView<T>
com.mysaloon.ui.core.model.IModel<T>
- параметризованы типом сущностей, отображаемых в основном списке журнала.
За обработку событий отвечает Presenter. Он реализует интерфейс EventHandler и посылает запросы на обновление View при обработке соответствующих событий. Например:
private void registerForEvents() {
EventBus.getInstance().addHandler(this, DataChangeEvent.class);
//... подписка на другие типы событий ...
}
public void handleEvent(Event e) {
if (e instanceof DataChangeEvent) {
onDataChange((DataChangeEvent)e);
} else if ... ...
private void onDataChange(DataChangeEvent e) {
mainView.refreshListFromModel(selectedItemIndex);
itemsCount = model.getItemList().size();
}
Диаграмма для Presenter’а и связанных с ним классов:
Серверная часть приложения реализована для варианта SmartGWT при помощи средств GWT для создания сервлета, обрабатывающего клиентские запросы. Вот фрагмент клиентского кода:
public class ModelSG<T extends Persistent> implements IModel<T>{
EmployeeDAO реализовано при помощи Hibernate …