This page outlines how the MvcIsNotImplementable puzzle can be addressed by a framework based on the architecture proposed in ModelTargeterSurface. It proposes in SuperAbstract terms an API for constructing interactive applications in object-oriented languages such as Java. - DavidWright
Two main forces act on the development of an interactive application. To enable the user transparently to access and modify domain data, the application must provide an interface to this data; while SeparationOfConcerns suggests that the code for the interface and for the domain should as far as possible be segregated.
There is general agreement that the ModelViewController paradigm offers insight into this problem, and on how to implement the model; but uncertainty and even controversy prevail as to implementation of the view and controller. As proposed in MvcIsNotImplementable, this difficulty can be resolved by regarding the user interface as a surface providing an application with view and control function over its model.
On this analysis, the primary goals of a Superficial (sorry, Brit irony) framework will be to
- facilitate development of application surfaces exposing domain data to user view and control
- enforce separation of surface and domain code
Superficial is based on the three-tier architecture outlined in
ModelTargeterSurface, in which two main tiers act as abstraction facades:
- a model tier for domain data and logic
- a surface tier for platform widgets providing view and control of the model
While the Superficial API resides almost entirely in these two tiers, an intermediate
targeter tier provides the targeting and multiplexing (defined in
ModelTargeterSurface) needed to link model and surface elements in any non-trivial application.
A Superficial model exposes the domain using a compact interface that minimises coupling between surface and domain. This interface nonetheless enables the surface to expose the model - and thus the domain - to user view and control in a powerful and transparent way.
- The domain need have no knowledge of the model, let alone of the surface; issues such as input validation and output formatting can be handled by model and surface.
- The surface need have minimal knowledge of the domain and only narrow knowledge of the model.
- A model can readily be defined that enables the domain to be exposed by a very rich surface, without prescribing or constraining the details of such a surface; indeed the same model can be used for surfaces of quite different kinds.
A SpikeSolution is needed to demonstrate how Superficial implements ModelTargeterSurface. This should
- have minimal domain code, probably generating its objects using a standard API
- expose domain objects with a wide range of properties.
- be extensible enough to demonstrate both elementary and more advanced features of the framework
These needs are met by a simple browser-hosted line art viewer, based on types easily created using
JavaAwt:
- _LineArtApplet
- Has a single _LineArtPlane on which are drawn the members of an immutable set of _LineArts.
- _LineArtPlane
- A graphics plane with a integer coordinate system. Could have properties such as backgroundColor, doAntiAliasing.
- _LineArt
- Has a mutable string text which it draws on its parent _LineArtPlane based on other mutable properties such as
- drawAtX, drawAtY - integer coordinates, must be constrained to keep the text visible within the viewer.
- drawAngle - stored in radians
- fontFamily - string selected from a fixed list
- fontSize - positive integer values
- fontStyle - ORed from integer constants bold, italic
- fontColor - one of a fixed list
- highlighted - flag telling the viewer whether or not to mark the drawn string in some undefined way
Here is a
UserStory about a surface that exposes these objects:
-
- "The browser has a window with several pieces of text drawn in different sizes, styles and colours, some at odd angles. Below the window is a button that allows you to change which text is highlighted. Other buttons and boxes let you change the highlighted text, its colour and size etc. You can move texts around and change their angles; you can't move the start of a text outside the window."
-
- "The functions of most buttons and boxes also appear in a menu bar above the window. In the basic version all you can do is switch bold and italic on and off."
Implementation now available via http://superficial.sourceforge.net
The model tier can use two different patterns when exposing domain objects to the surface:
- decorator(-like) - add functionality while leaving the domain object visible
- facade - completely conceal the domain object
There are trade-offs between these approaches. Since a decorator leaves the domain object visible to the surface, it need itself only support targeting and multiplexing. However the surface element providing view and control of a decorated domain object needs detailed knowledge of the domain object's interface, leading to undesirable coupling between surface and domain.
By contrast a facade completely decouples surface and domain objects, but must extend the basic targeting and multiplexing interface so as to describe the domain object fully to the surface.
A practical compromise is to expose domain primitives using the facade pattern, and other objects using compositions of facades as far as possible and the decorator pattern where necessary. Only a few facade types are needed:
- Triggering
- The simplest: analogous to JavaSwing Action, starts a domain or application process. Exposed in surface by buttons and menu items, and by keyboard input.
- Toggling
- Gets and sets a flag (boolean) value. Exposed in surface by checkbox buttons/menu items.
- Textual
- Gets and sets a string (other than the element's identifying title described below); may constrain content or format. Exposed in surface by text fields and areas, status lines.
- Selecting
- Gets a list of items, gets and sets an index into the list. Exposed in surface by list and combo boxes, spinners, iterator buttons, radio buttons/menu items.
- Numeric
- Much the most complex: gets and sets a value up to the accuracy of its implementation (which should of course be a double). Uses internally and also gets both its domain constraints (eg to integer values within a range) and presentation values such as tick spacings. Exposed in surface by sliders, spinners and buttons, formatted text fields, progress bars.
These facades would be less straightforward if they had to allow more detailed modification such as insertion of text or of items into selecting lists. However
ModelTargeterSurface is particularly suited to
BruteForce solutions: facades can be discarded as required and fresh ones created from the underlying domain objects.
The basic features of all model elements, both the facades described above and decorators for complete objects, are captured by a small Exposable interface which is used by Superficial as the basic protocol for communication between model and surface:
- elements
- Immutable list of other Exposables enabling the element to expose a domain object composed of primitives and/or other objects; also allows a single facade element to aggregate logically related elements such as undo and redo triggers, groups of togglings.
- active
- Flag used by the surface to enable/disable platform widgets.
- title
- String for use 'as is' in the surface or as a key to retrieve suitable icons and localised strings.
- source
- The complete domain object (if there is such) that the element represents.
There are three variants of Exposable. Whether an element is 'sourced' or 'sourceless' is marked by a
Model variant of a base
Target type; while a
Targeter variant is required to link model and surface elements. Adding a
Surface type for an exposing peer in the surface tier, the set of types defining the essence of Superficial is thus limited to:
- Target
- Facade for one or more domain primitives, any elements will be other Targets. Limited variation as described above to represent different primitive types.
- Model
- Decorates a complete domain object, elements may be Targets or other Models representing the object's composing primitives and objects. Unlimited trivial variation to represent domain objects; some real variation to create application objects, especially _SelectingModel to set paths through the target tree.
- Targeter
- Can be retargeted to any compatible Target/Model, for which it acts as a link to an arbitrary number of Surfaces. Variation as required to target model variants.
- Surface
- Linked by a Targeter to a Target in the model tier for which it provides view and control.
The elements of a
_LineArtModel can thus be (in order of complexity):
- fontStyle - group of togglings for bold and italic.
- fontFace - Selecting of strings.
- fontColor - Selecting of colors.
- text - Textual; possibly constrained to remove duplicate spaces and non-alphanumerics
- drawAngle - Numeric converting radians to integer-constrained degrees normalised to between 0 and 360.
- fontSize - Numeric constrained to positive integer values; possibly coupled with selecting of commonly required values.
- drawAt - pair of numerics constrained to integer values within the drawing pane; possibly coupled with shared selecting of tick spacings and shared toggling to set snapping to tick marks.
The
highlighted property can be accessed during retargeting via the model's
source property.
_LineArtModel includes no example of the essentially trivial Triggering, but does demonstrate how target primitives can be defined and grouped so as to expose domain values, their constraints, logical relationships and presentation hints.
The _LineArtModel constructed for each _LineArt is of a concrete type to capture these details for the domain type. However it is handled internally by Superficial as a simple target and its targeter is constructed dynamically based on the first instance to which it is retargeted. Any number of surface elements can then be attached to each of the link elements returned by this targeter, of any type compatible with the links' targets.
For example a complete 'drawAt' model element is handled by Superficial as a single target. When the targeter link for this element is constructed, it creates its own link elements for the two numerics returned by the 'drawAt'. A wide range of surface peers can then be constructed for the main link, each providing view and control of its elements' target numerics; these can be combined with surface peers of the shared selecting and toggling, created from link elements in the application targeter. For instance:
- a pair of sliders representing the current coordinates in relation to the view area, with major tick marks set to the currently selected spacing
- a pair of numerical fields, with increments constrainable to the current spacing
- a similarly constrained pair of spinners
- a similarly constrained pair of nudge buttons or menu items ("Up" and "Down", "Left" and "Right") for each coordinate
- a dropdown list, sub-menu or set of menu items exposing the available tick spacings
- a check box or menu item constraining changes to the current spacing
- complete menus or panels combining any of the above elements
As all the information required to create and update surface elements is accessible via their targeter peers, they can readily be created by passing Targeter references to abstract factory methods eg
Surface newSliderPanel(Targeter link,int sliderWidth,int displayHints);
As the foregoing implies, the tiers of a complete Superficial application are constructed in sequence:
- 1. Model
- One or more content models expose domain objects for which the user needs view and control; these are referenced by an application model managing the surface viewer(s). Both models are and/or contain _SelectingModels to define target paths.
- 2. Targeter
- The root targeter for the application is retargeted on the model, dynamically creating a targeter tree which exposes the current target paths.
- 3. Surface
- Panels, pull-down menus etc are constructed out of surface elements defined quasi-declaratively for elements in the targeter tree; these are then passed to the platform host which lays out the necessary widgets.
The simplest content model may be just a _SelectingModel exposing an immutable list of domain sources. The simplest application model contains its content model and some viewer settings; a complex one may comprise a substantial target tree exposing several documents (each with its own content model) in multiple custom viewers.
Once the surface has been constructed and its elements display the state of their current model peers, any model peer can updated by any of its surface peers in response to user input. When a model peer is updated - from the surface or otherwise - it notifies the application which retargets the application targeter; this in turn notifies all its surface peers, which update their platform widgets as required. By the end of the update process the application surface is guaranteed to represent the latest state of all currently targeted model elements.
Thanks to its abstract nature the targeter tree can be connected to a range of different surfaces. Instead of a managing a set of GUI widgets the surface can be a a command-line interface addressing targeter elements individually; for a web application the serialized targeter tree can be transmitted to a proxy in the user's browser, with updates transmitted back in command-line syntax.