В течение некоторого времени я тихо взламывал инструмент отчетности Eclipse Business Expense Tool (EBERT) из проекта «Примеры». Моя цель — превратить это приложение в яркий пример того, как можно создать реальное (хотя и относительно простое) приложение на основе Eclipse RCP , eRCP и RAP .
Мне было неловко, чтобы разобраться в координации взглядов. Приложение состоит из трех видов. В версиях RCP и RAP представления составляются, как показано ниже, с BinderView слева, ExpenseReportView вверху справа и LineItemView внизу справа. В версии eRCP, представления сгруппированы и выборочно представлены.
Сначала я использовал сервис выбора для координации видов. Например, ListViewer в BinderView настроен как поставщик выбора, а ExpenseReportView настроен как потребитель выбора: когда ExpenseReportвыбран, ExpenseReportView обновляется сам. Хорошая особенность этого механизма заключается в том, что он позволяет полностью отделить представления друг от друга, а также позволяет другим представлениям выступать в качестве поставщиков выбора. Еще одна очень приятная особенность использования службы выбора для этого заключается в том, что она хорошо работает в многопользовательской среде RAP, поскольку каждый пользователь получает свою собственную копию рабочей среды (и, соответственно, свою собственную копию службы выбора). С другой стороны, управление такими вещами, как, например, случай, когда, например, выбранный ExpenseReport удаляется, требует некоторой работы (когда ExpenseReport удаляется из BinderView, следует ожидать, что ExpenseReportView и LineItemView станут пустыми). Это не особенно трудно справиться с этим, но кажется немного грязным. Это,и служба выбора на самом деле не реализована в eRCP (потому что она действительно бесполезна в этой среде).
Я решил вместо этого ввести класс ViewModel . ViewModel предоставляет, как следует из названия, модель моего представления. Для этого приложения модель представления довольно проста: она отслеживает «текущие» ExpensesBinder , ExpenseReport и LineItem . Различные виды все говорят модели представления о действиях пользователя. Модель представления обновляется в ответ на эти действия и уведомляет различные представления об изменении.
Когда, например, ExpenseReport выбран в BinderView, модель представления информируется об изменении:
// TODO Consider using addPostSelectionChangedListener instead expenseReportViewer.addSelectionChangedListener(new ISelectionChangedListener() { public void selectionChanged(SelectionChangedEvent event) { IStructuredSelection selection = (IStructuredSelection)event.getSelection(); getViewModel().setReport((ExpenseReport) selection.getFirstElement()); } });
Модель представления отвечает, устанавливая «текущий» ExpenseReport, установленный на недавно выбранный, и «текущий» LineItem должен быть нулевым. Затем все слушатели информируются об изменении. Код представляет собой довольно простую реализацию шаблона наблюдателя :
public void setReport(ExpenseReport report) { this.report = report; this.lineItem = null; Object[] listeners = listenerList.getListeners(); for(int index=0;index<listeners.length;index++) { IViewModelListener listener = (IViewModelListener) listeners[index]; listener.reportChanged(this.report); listener.lineItemChanged(this.lineItem); } }
Каждое из представлений слушает модель представления. Когда наблюдатель уведомляет их об изменении, они реагируют соответствующим образом. Например, LineItemView отвечает на метод lineItemChanged (LineItem), обновляя себя, чтобы отразить изменение:
IViewModelListener viewModelListener = new IViewModelListener() { public void binderChanged(ExpensesBinder binder) { } public void lineItemChanged(final LineItem item) { syncExec(new Runnable() { public void run() { setLineItem(item); }; }); } public void reportChanged(ExpenseReport report) {} };
Другие типы и представления обрабатываются аналогичным образом.
Самой большой проблемой при таком подходе является, конечно, многопользовательская среда RAP. Чтобы справиться с этим, мне нужно было придумать понятие состояния пользователя. Модель представления является лишь частью состояния пользователя.
Я поговорю об этом в следующий раз …
Пожалуйста, сделайте это, если есть что-то, что можно сделать лучше.