Model View Controller
Model View Controller (MVC) is an architectural pattern used to separate domain objects which model our perception of the real world and the presentation objects used which are the GUI components that we see on the screen.
A few key points regarding domain objects: * domain objects should be completely self contained and they should work entirely without reference to the presentation.
- domain objects should support multiple presentations, possibly simultaneously
- domain objects send events when it’s state changes to allow views and controllers to observe those events
In MVC, the domain element is referred to as the model. Domain objects are to represent their real world counterpart. For example, a domain object for a person would be a Person object.
The presentation (UI) part of MVC is the view and the controller.
- the controller’s job is to take user input and figure out what to do with it
- the view’s job is to be the UI (The view should contain as little to no logic as possible.)
There is a model-view-controller for each element on the screen.
Some important notes about the design of MVC:
- the model object does not contain a reference to the controller or the view
- the controller and the view contain a reference to the model
- the controller and the view do not contain references to one another
- the controller and the view observe the model object for events/changes
The design of MVC shows that the controller does not directly update the view. Instead it notifies the model, and lets the observer mechanism take over. Since the view is observing the model object it should update itself accordingly.
Issues With MVC
Issue #1 - View Coupling
Since a model, view and controller exists for each UI element on the screen, MVC can fall short when an update in one view propagates a change in a different view. This is because you can end up with coupling between views:
- having one view update another view couples the views
- you can solve this by creating a new view which is composed of the previous two views
Issue #2 - View Logic
A second issue which is a variant of the first issue exists when an update in one view propagates a change to itself or another view which is based on criteria based on the change in the domain object.
The problem with the second issue is that you have logic that makes a decision about the presentation of your model. The logic to do this isn’t necessarily domain logic so it doesn’t belong in the model. You also don’t want to put unnecessary logic in the view.
You can solve this by: * creating a new model object that is oriented around the screen (presentation) which wraps the original model object. The view logic could go in this model object without affecting the original model object. (this would be equivalent to creating an intermediate Presentation Model object to handle the view logic)
According to Fowler, the Presentation Model also allows you solve the issue of presentation state, as well as presentation logic. By wrapping the domain model in a presentation model you can maintain view specific logic and state separate from our domain logic. All the while leaving the view very clean.
Issue #3 - View Testability
Testing views is extremely difficult. This is one of the reasons why MVC suggests to leave views as simple as possible, because they are hard to test.
You can reduce the risk of issues in the view by moving most, if not all of the logic outside of the views into domain objects or presentation model objects which can be self-contained and are easier to test.
MVC is the building blocks for breaking out domain logic from presentation logic.
Testing a strict MVC architecture seems to have its drawbacks especially if complex view logic is kept in the view. The overhead of creating a model/view/controller for each UI element also seems to be a daunting task to coordinate and test.
Rather then strictly following MVC it seems to be a better approach to utilize a MVP approach.
Model View Presenter
Model View Presenter (MVP) is a architectural pattern similar to MVC. Whereas in MVC there is a controller/view for each UI element, in MVP there is a typically a single presenter/view for each for screen or at the least for each set of complex screen elements.
MVP and MVC share the commonality that they both rely on the observer synchronization. In MVP the presenter handles user actions and updates the model. In MVC the controller handles user actions and updates the model. In both MVP and MVC the view will then be updated by observing events/changes on the model.
MVP implementations can vary in a great deal when it comes to how the view gets updated: * one variation maintains the same relationship between the model, view and presenter that is maintained through MVC’s relationship of the model, view and controller. * a second variation allows the presenter to have access to the view to update the view when complex view logic is required, otherwise view logic would go in the view. Fowler refers to this as the Supervising Controller (aka Supervising Presenter). * a third variation puts all of the view updates inside of the presenter. This implements what Fowler refers to as a Passive View. * a fourth variation of this is implemented in the Presenter First pattern. (this will be describe later)
MVP simplifies complex view updates by utilizing a Supervising Controller. By extracting out complex view logic is promotes greater testability for your application.
Allowing a presenter object to handle the user actions for a screen, form or set of UI elements seems to cut down on unnecessary complication and overuse of observers as you could get with MVC.
The Presenter First (PF) approach is a variant of MVP. In practice the authors emphasize using it in an agile development process which build features into an application given customer stories. It is considered to be a hybrid of process and pattern.
To outline some of the things PF does:
- separation of business logic and view logic
- separation of complex view logic from the view
- decoupling of the view from the presenter/model
- provide fully testable GUI applications
PF works by composing the model and the view into the presenter via dependency injection. The presenter is created, but is never reference throughout the application. It simply glues together the model and view.
The model nor the view contain a reference to the presenter. Instead they send events that the presenter observes, and the presenter then coordinates those events and updates the model or view accordingly.
View —-> Presenter <—- Model
PF states that the view is the most complex, tedious and time consuming component to test. PF’s goal is to leave the view as simple as possible. One way it promotes to do this is to only allow your view to manage simple data types. If complex data types are handled in your view, then your view must contain the ability to process and correctly display the complex data types. Since this promotes additional logic in your view, PF discourages this.
PF ties user stories directly to a specific MVP triplet. The term “triplet” is used to refer to an instance of a model, view and presenter. Triplet is commonly referred to as a “triad”.
PF takes into account that complex view logic that exists. Often times that logic is mixed in with the domain objects. The problem with this is that the domain objects now contains a mixture of domain logic and view logic. This makes the code harder to read and it complicates the interaction between the model, presenter and view because complex view updates are propagating from the model itself.
PF solves this by introducing an “adapter” object. The adapter object goes in between the view and the presenter. The presenter will now reference the adapter, and the adapter will reference the view. There now exists a place that isolates any logic that is needed for the view. View logic is now fully testable.
Also, the adapter object may lead to an adapter-model object in which only the adapter would reference. This could be used to maintain view/presentation state. Even if an adapter object is introduced, the term “triplet” is still used.
PF also suggests that the presenter objects have no public methods and that they are stateless. The presenter’s job is merely to coordinate events between the view and the model (or vise versa).
PF also suggests that starting with the presenter first is the best place to start the development of a user story. Over time PF suggests it is less expensive to start with the presenter, rather then the view or the model.
Presenter First promotes a consistent, predictable convention for class naming, and object responsibility. It allows for IDEs or development tools to be created to speed up the development, creation and testing of these objects.
The interaction between the components in PF is easy to understand and the way that it is approached by the authors seems to remove issues with more classic MVC patterns or other MVP variants.
blog comments powered by Disqus