|
Model GUI Mediator Pattern
-Andy Bulka, July 2000 abulka@netspace.net.au This page may not print that well (blame FrontPage? - any suggestions appreciated) or download the printable pdf version. Latest News: May 2003 - Andy Bulka responds to a A MGM Pattern question from Khanh Cao.
AbstractA MGM object displays a portion of a software applications data to the user, and optionally allows that data to be altered by the user of the application. MGM is specifically suited to the display of application data in contemporary, off-the-shelf GUI control widgets within a modern RAD (Rapid Application Development) IDE. The MGM design pattern empowers a programmer to simulate "object-aware" controls using off-the-shelf GUI controls. Intent To manage the display and user manipulation of model data using off-the-shelf GUI graphic controls / widgets. Like Model-View-Controller (MVC), the MGM solution keeps graphical knowledge out of the model, decoupling the model data and GUI. Overview Consider the following scenario:
Figure 1. You can change Mary's age by using either the text box or the slider control.
Discussion The MGM (Model-GUI-Mediator) pattern balances the basic forces of the model to GUI mapping problem in a different priority than MVC (Model-View-Controller), because it introduces a powerful new force that of being relevant to a modern programmer who wants to use off-the-shelf GUI controls within a modern RAD (Rapid Application Development) IDE. Delphi, Visual C++, JBuilder, C++ Builder, VB etc. are examples of such environments. Such environments have a built-in event handling framework for such GUI controls, where the programmer can easily add code to respond to various events e.g. the OnTextChanged event. Unlike MVC, MGM works well in this context The MGM pattern encourages designing and programming in terms of a proper object model. Unfortunately, the convenience of off-the-shelf data-aware controls is often compelling due to the easy, instant mapping of GUI controls to relational database data attributes and the subsequent automatic synchronization between those GUI controls and database data. This situation encourages programmers to adopt relational database technology to model their application. This is often overkill and introduces a dependency on relational database engines. This in turn increases application size, makes application installation more complex. Most of all, it discourages programmers from designing and coding their application in terms of a pure object model. The MGM pattern on the other hand, encourages the use of an object model instead of a relational database model, since some of the convenience of object-aware GUI controls can now be simulated (though you will still need to implement your own persistence functionality). Also Known As Model-View-Graphic (MVG) [Jezequel, Train, Mingins 2000, "Design Patterns and
Contracts"] Solution The Model GUI Mediator pattern is actually 2 classic patterns overlaid on each other: Mediator and Observer. A mediating view class mediates all communication between the GUI component and model. The model communicates with the mediating view(s) using observer. MGM uses the following terms:
The interaction of the observer pattern notifications, the GUI control event notifications and the view objects mediation in the MGM pattern are illustrated thus: Fig. 2. How the MGM view class mediates. How to implement MGM In a nutshell, assuming your model already implements observable, (1) derive a mediating view class from observer, code its update method to display a business object attribute in a GUI control. (2) Subscribe the mediating view object to a business object, point the mediating view object to a GUI control and point the GUI control to the mediating view object. (3) Using your IDE framework add GUI event code that responds to events and modifies the business object via its mediating view object. (4) Ensure any relevant business object attribute changes trigger a NotifyOfUpdate broadcast (observer pattern). Detailed steps are listed below: Here is an example implementation of the MGM pattern: Fig. 3. MGM pattern for use with off-the-shelf GUI controls.Comments boxes contains fragments of Delphi Object Pascal code Detailed Steps:
Customer23.attach( Customer_NAME_TextEdit_MediatingView1 ); Customer27.attach( Customer_AGE_TextEdit_MediatingView2 ); Customer27.attach( Customer_AGE_Slider_MediatingView3 );
Delphi Object Pascal code. procedure Customer.SetAge( newAge: integer ); begin _age := newAge; // Set the private field representing the customer's age. NotifyOfUpdate; // Loop through attached observers & call Update on each. end;
Delphi Object Pascal code. procedure Update; begin EditControl.Text := Subject.userText; end;
MediatingView1 :=
TCust_AGE_TextEdit_MediatingView.Create( edit1 ); A note on tags: A GUI controls 'tag' property may be called something different in your particular IDE. In Delphi & Visual Basic its called tag. In X-windows its called a resource. In Visual C++ under the Microsoft Windows environment you can associate a 32-bit value (e.g. a reference to an associated mediating view object) with a control using SetWindowLong/GetWindowLong which are Windows API functions so this is not a solution specific just to C++ : Simulating the tag property using Visual
C++ code ::SetWindowLong( aEdit.m_hWnd,
GWL_USERDATA, (long) pMediator ); The above is C++ code: procedure GUIControl.OnTextChanged (Sender: TObject); mediator := MediatingView( Sender.Tag ); // Cast generic tag into View type. mediator.Subject.userText := Sender.Text; // Sender is a ref to a GUI Control. end;
Delphi Object Pascal code. Notice that the above OnTextChanged code does not need to call mediator.Subject.NotifyOfUpdate since the setter function Customer.SetUserText found on the subjects userText property would have already called .NotifyOfUpdate (see step 1.3) procedure GUIControl.OnTextChanged (Sender: TObject); mediator := MVRegistry.FindMediatingView( sender ) // Sender is a GUI Control ... ... end; Delphi Object Pascal code. Thus the resulting mediating view class acts as a mediator linking the interface of the GUI control to the interface of the business object/model. Another way to look at it is that the mediating class adapts the interface of the GUI class so that it can observe the model. The MGM mediating view perhaps might also be characterised as a type of two-way adaptor (GOF mention this term). The mediating view class encapsulates the role of presenting the business object data onto the GUI and in the other direction, of modifying the business object as a result of user actions in the GUI. Where a smart GUI component is not being used, it is entirely possible for the mediating view class to draw a complex series of paint/draw operations onto a dumb canvas. Again, having the detailed drawing logic reside in the mediating view object, is a neat way of encapsulating that logic. Why not MVC? Why not use the classic Model-View-Controller (MVC) instead of Model-GUI-Mediator (MGM)?
Why not Document-View? The Document-View (DV) architecture combines the roles of MVCs view and controller into a view class. Typically used in a Microsoft C++ multiple-inheritance environment, GUI control widgets, especially GUI forms, are sub-classed from the view class, which implements observer. The model, in order to benefit from being observed, inherits from the document class. DV users often avoid sub-classing GUI controls by introducing an adapter class which inherits from the view class. The resulting pattern then closely resembles MGM. MGM Variations There are a number of variations of the MGM pattern. These variations are generated by the type of association between the model and the mediator, and between the mediator and the GUI. A notation for these variations might be of the form model-mediator, mediator-GUI. Thus 1-1, 1-1 would represent the classic one-to-one-to-one MGM pattern: The classic 1-1 , 1-1 configuration The next interesting variation of the MGM pattern is one business object to a number of mediator/GUI pairs. The notation for this would be 1-*, 1-1. This configuration would be useful if you wanted to display different attributes of the same business object, or the same attribute in two different GUI controls:
or 1-*, 1-1 1-*, 1-1 Alternatively, a single mediator could take on the responsibility for maintaining multiple GUI controls, although this may have the disadvantage of a single mediator with too much responsibility:
1-1, 1-* A less common variation of MGM is that of multiple mediators feeding into a single GUI control. This is useful for logging information functionality. One can log aspects of single or multiple business objects. Where the GUI control is read-only, the GUI need not point back to the mediating view, nor is there any need for GUI event code: 1-1, *-1 Variations based on Composite GUI components
1-1, 1-1 This 1-1, 1-1 treeview configuration could be used, for example, to display all the business objects in your model on a treeview. A single attribute of each business object e.g. name would be the visible representation of each business object on that treeview. Incidentally, if MGM has been implemented correctly, then the users in-place editing of a GUI tree node would alter the value of the name attribute not only on the treeview, but also in the associated business object. A variation of the treeview configuration is to reduce the number of mediators to one, at the risk of making the mediator heavy in responsibility: 1-1, 1-* Such a single mediator looking after many GUI sub-components might be more appropriate when only a single business object is involved. For example, many aspects/attributes of the same business object are being displayed by the one mediator onto a treeview GUI control. Variations based on Manager Objects More variations of MGM revolve around aggregating not only GUI controls, but mediators and business objects as well. Such Manager objects can provide functionality for collections of MGM objects. For example, a model business object manager might offer persistence functionality for a collection of business objects. Some mediating views might actually subscribe to and observe business object managers rather than individual business objects. Such managers would observe business objects, and be observed by mediating views. For example, a read-only GUI text label displaying the number of objects existing in the model would be implemented as follows: a ModelObjectCounter mediating view object would be created and would subscribe to the model manager object. When triggered, the mediating view would ask the manager object for the number of business objects that existed and display this number in the appropriate GUI text label control. Manager objects are also useful on the mediating view side of things. A view populator class should probably be created and be responsible for the important step of creating the initial set of mediating view objects and setting up the relationships between the GUI controls, mediators and business objects (especially for composite GUI controls like treeviews and their nodes). This might include either setting up tag pointers in GUI controls or adding entries to a central mediator to GUI mapping registry. The View Handler pattern (POSA) can be used to manage various view managers. More ambitiously, composite, and other various patterns of mediating views might be formed in order to systematically and generically compose an interface (see MVG). Limitations Replacing either the GUI control or business object will affect view mediator code and property types. For example, replacing a text edit control for a masked text edit control (e.g. the new GUI control does some neat validation) means rewriting the mediating view class slightly to deal with the new GUI control. At the very least, the pointer type from the mediating view class to the GUI control has to change (unless the pointer to the GUI control is to a generic base GUI control class). Alternatively (and perhaps preferably), for each new GUI control, a new mediating view class should be created that specifically points to and has code to handle that new GUI control. Creating a new class for each business object to GUI control mapping results in a proliferation of mediating view classes. To reduce the number of mediating view classes more generic mediating views could be introduced which could handle a wider range of GUI controls, or a broader set of business objects or business object attributes. For example, a CutomerTextEdit mediating view class could handle the display of any customer attribute in a text edit control. A technique for specifying to the mediating view class exactly which attribute to display would need to be invented. There is a trade off between placing code that modifies the business object in the GUI event handler, or putting that same code in the mediating view class in order to keep the GUI event handling code simple and to keep model knowledge encapsulated within the mediating view class. For example, when the user changes the contents of a GUI text field, the GUI event handling code can ask the mediator for the relevant business object, and modify that business object directly. Alternatively, the GUI event handling code could simply notify the mediator, and let the mediator handle the details of the change to the model. Keeping model changes encapsulated in the mediating view class is probably the cleanest solution, minimizing the impact of swapping one GUI control for another. Consequences All the forces are resolved in the MGM pattern solution, however there are the various issues raised in the limitations section to consider. If any forces could to be said to be less fully resolved these would fall under the category of encapsulation & loose coupling (see forces 12 & 13). The GUI can potentially still know too much about the model if implementations allow this, though in most cases this may not be such a bad thing as long as the more important principle is adhered to: viz. that the model is ignorant of the GUI. Another consequence is that we now need to manage collections of view objects, including their initialisation and shutdown. As mentioned earlier, variations of the View Handler pattern might be used to help deal with these new forces. More ambitious composite views would involve even more design, pattern! and coding work. Known Uses Reason! Software for critical thinking (1998-2000), Melbourne University, Australia uses MGM for various treeview and combo box displays. Dolphin Smalltalk 98 - All of the Dolphin development system tools are built using the MVP (Model View Presenter) framework. MVP is similar to MGM in that a mediating presenter class plays the key role, as the mediating view class does in MGM. Large scale South African / Australian client server based car management system 1999 uses MGM for all GUI displays. Latest News and Discussion
Latest News: May 2003 - Andy Bulka responds to a A MGM Pattern question from Khanh Cao.
This page may not print that well (blame FrontPage? - any suggestions appreciated) or download the printable pdf version.
-Andy Bulka Copyright (c) 2000, Andy Bulka, All Rights Reserved. |