These notes represent a summary of my presentation “Leveraging the Model-View-Presenter Pattern in Rich Applications” at Eclipse World 2008. Unfortunately I wasn’t able to give the presentation due to a family emergency. I hope that these notes will give you some sense of what the talk is about.
What this talk is about
The purpose of this talk is describe how the MVP pattern can be leveraged in Eclipse Rich Client Platform applications to make your code more flexible and testable.
A brief history lesson
All architectures assume some separation between UI and non-UI logic. These architectures historically have taken three forms.
- Forms and control
The benefits of model-view separation should be familiar to most of us. The biggest benefit is the ability to view a single model type in a variety of views.
The most basic type of model-view architecture is what is sometimes called Forms and Controls. This is an architecture in which a form updates the model when notified to do so by individual controls. This can be achieved through event listeners or data binding. In an RCP application, forms can be views, editors, wizards or other dialogs.
MVC is a pattern which introduces the concept of a controller that is responsible for mediating between views and models. Controllers make sense for some architectures and not so much for others. Web applications typically have a controller such as a servlet that prepares data from the model and supplies it to the view.
The MVP pattern is an attempt to assign a more meaningful role to the space between models and views. There are various flavors of this pattern that have been identified, particularly by Martin Fowler, and I’ll be discussing those in this talk.
Presenter pattern in detail
The presenter pattern is based on the concept that there is UI logic that is not UI-dependent. This logic may be related to validation, control enablement and display (colors, fonts, etc.), and in MVP this logic is off-loaded onto a presenter class tied to a particular view.
Presenters are usually tightly coupled with a particular view. You may have many presenters for the same model type.
Store presenters in their own plug-in and (if possible) have this plug-in not have UI-dependencies.
First benefit or MVP is that it allows us to flexibly reuse presenters. It does so by allowing us to segregate our code into UI and non-UI concerns. It is possible to reuse presenters with various view technologies including RCP, RAP and potentially with Flex and other web UIs.
MVP also drastically increases our ability to test UI logic. Unit tests of presenter classes can come to resemble acceptance tests. These tests would set variables into a presenter and then make assertions about validations, control enablement, colors and much else.
MVP defines three data states: record, session and screen. The record state represents the model as it is stored on a database or in a file. Session state is the current state of the model data as it is stored in the presenter itself. Finally screen state is the state of the model as it is displayed in the view.
Typically, the view will move data down into the presenter as the view is modified. Moving data to record state occurs when the user requests that the model state be persisted in some way.
MVP and RCP
Again, presenters should be stored in their own plug-ins and not mixed in with UI classes such as views and editors. This will allow you to reuse presenters in situations where the Eclipse UI plug-ins are not present.
It’s a good idea to create an abstract presenter that all other presenters extend. This abstract presenter is a good place to put property change management logic to support data binding.
Then extend this presenter superclass and create abstract presenters for each of the major types of RCP UI elements (editors, views, wizards, wizard pages, etc.). Each of these presenters can provide methods appropriate to the UI element. For example, an editor presenter can provide save() and isDirty() methods.
Data binding can be done in either the view or the presenter. If done in the presenter, the view will need to expose it’s controls via accessors. In this case, it’s a good idea to expose the controls as IObservable instances so that no UI dependency is created.
It is somewhat simpler to implement data binding in the view and this is the approach that most projects I’ve worked on have taken. Implementing data binding in the presenter can also complicate unit testing, as your assertions have to rely on bindings being operational during the tests.
Validation is also problematic with data binding as a failed validation will cause the data to not be transferred to the presenter. This may be what you want, but it’s often desirable to allow the presenter to contain invalid data and then prevent this data from making it to the model. To make this work, you’ll need to pull validation out of the bindings, but you can still use the data binding validation types.
What’s the big idea?
MVP and RCP work seamlessly together and this combination allows you manage complexity, increase reusability and improve testability. As OSGi and RCP mature, it’s likely that you will have many more choices when creating user interfaces. Adopting the MVP pattern now will set you up to take advantage of these opportunities in the future.