Hi folks,
I am still reviewing the Spring RPC code and I noticed lots of *Model* classes. There are tree models and adapter for those (*.binding.swing + various other packages). I guess 25% of all Spring RPC classes are about models!
I guess this is a big flaw of the API! After some serious thinking, I came to the conclusion that the view model thinking of Swing is a flaw in itself and imposes more harm than use.
Question: Is he crazy to question MVC?
Answer: In this case? Sure!
MVC means Model View Controller. We seperate the model from the way we view the model and we seperate the controlling aspect out of the others. This is a strong pattern when being used the right way.
But creating special models for using a certain kind of viewer is crazy! Think about, well Eclipse JDT - meaning the extension to the Eclipse platform allowing you to edit Java code and manage Java projects. Or more general speaking, let's talk about a Java IDE as a Spring rich client application.
First of all, what is this application about? -> Managing Java source files -> Managing the dependencies between them! (this allows easy refactoring, on the fly code validation and semantic checkings, code assistance etc)
So how would we implement a Java IDE?
-----------------------------------------------
I would design the domain including the basic domain model(!) and the basic business logic. Then I would go for the presentation layer and design the main views.
After laying the ground work, I would let the code drive me and switch to test driven development mode (writing tests about the feature before implementing the feature). Redesign the whole on every milestone.
Ok can be done in Swing - So what?
------------------------------------------
Noticed that I marked the domain model? This means we already have a model.
Whats the task of a presentation layer? - Providing and implementing the user interface - meaning providing views about the model and handling user interaction like typeing stuff, selecting stuff, CRUD operations (Create, Read, Update, Delete) and so on.
The presentation layer is about views, editors, windows things and so on.
And what is wrong about the View Model?
-----------------------------------------------
Nothing in general. But think about having an outliner of the java type the user is currently editing. An outliner view is about to show a tree viewer about all the methods, inner classes, class attributes this type has. Check your Java IDE, every Java IDE provides an outliner view these days.
So what is needed to implement the outliner?
----------------------------------------------------
1. We have to show the children of the type within the tree.
2. We have to handle selections of a child to enjoy the editor focusing on the selected element -> Outliner is about navigating the code!
So now lets takle this implementation with swing!
In Swing we would use a JTree. We would desing a TreeModel to be the model of the JTree, saying what items the outliner has to show. The items the outliner has to visualise depend on the type currently visible in the editor. So whenever the Java source changes we need to update the outliner view -> resulting in updating the model of the JTree. (already guessing what I mean?)
So we update the TreeModel, so what?
--------------------------------------------
In our Java Type Outliner example updating the tree model is about keeping the tree model in 'perfect' synchronization with the editor model (model about the current source of the edited type).
So in the TreeModel world (Swing world) our simple task -> Visualizing the structure of a Java type results in solving the task: Keep the TreeModel in total synchronization with the model the editor already (!) has about the type.
We have to solve the synchronization task for sure, but designing a special model? That's like wasting time!
And what makes the Content Provider pattern supiror?
---------------------------------------------------------------
See a content provider as an adapter. You translate the need to provide content to a tree viewer (solves the same task like JTree) into the need to make the tree viewer to understand the type model the editor uses / provides.
In both implementations your outline view needs to gether informations from the editor (editor makes part of his model visible). So you might implement something like:
So this is a simple way to represent a type. The structure does not impose cycles (forbidden within java code) and - we are in luck - it is tree like.Code:Editor { JavaType getCurrentType(); } JavaType { JavaType getSupertypes(); JavaAttribute getAttributes(); JavaMethod getMethods(); JavaType getInnerClasses(); }
Also the editor provides a listener service so the outliner keeps in touch with the changes made to the type. The change events would be something like: TypeStructureChange-> Method Changed, Method Added etc.
So in Swing you would hook up the outliner and listen for changes. Update model according to the changes and you are done. So you have to design a special tree model and go for it.
In the Content Provider world, you would hook up the outliner and listen for changes, too. But you only would provide a way for the tree viewer to react towards the changes.
A tree content provider would look like this:
How to notify the tree viewer about a change?Code:OutlinerContentProvider { getToplevelElements() { return editor.getCurrentType(); } getChildren(Object element) { if(object instanceof JavaType) return type.getMethods+type.getAttributes+type.getInnerClasses else return nothing; } hasChildren(Object element) { return getChildren(element).length>0 //lazy } }
TreeViewer.refresh(subtree rootobject to refresh);
TreeViewer.refresh(); //refresh all
We are done folks! No collection to be provided, no caching, no nothing. Now try to do the same with a special TreeModel implementation! (ok you can hack around it but it still is a model we are talking about)
By the way labels of the tree (Icons+text) are provided by using a LabelProvider looking like this:
A tree content provider also is able to serve as a content provider for lists. Remembering the getChildren(Object inputElementOfList)? Done!Code:LabelProvider { getText(Object element); getIcon(Object element); }
So the same content provider can be used for tables? Done!
Ok can you give me a design explaination why the ContentProvider Pattern performs so much better?
----------------------------------------------------------------------------- --------------------------------------
Sure.
You are composing the view using certain viewers (JTable, JTree, JList etc). Providing a view is about making something visible to the user, that is already known and well understanded. (In our example this is the object representation of a java type (JavaType+JavaMethod+JavaAttribute)). So if something is well understanded, it means that there is a model about it. (Being called domain model or something others like an AST, XML document...). So why do we need to create an additional and special model just to feed JTree, JTable,JList?
So within a certain view, the viewer being used to compose the view impose dependencies backwards toward the design of the view. This is reveresed responsibility!
First design rule is: Don't model same thing twice! (TreeModel vs DomainModel)
Second desing rule: Don't translate from one data representation into another (TreeModel vs DomainModel).
Or think about this scenario:
Implementing a view, you need to understand, what you want to view. Maybe it's better to have an outliner model. So we implement an outliner model. But this model wouldn't be about trees and TreeModel.
Never let viewer requirements drip into your view requirements and never let presentation requirements drip into your domain layer. Think about presenting an additional table within the outliner. The table presents all methods of the type + its lines of code (complexitivity measure). In the Swing world we need to provide a TreeModel and a TableModel. So someone would like to extend the outliner model to store Lines Of Code measures for all the methods. Then the TreeModel and TableModel are synchronized with the outliner model (or the outliner model is three model in one - ARGH!). Now we have tree models. One being a tree model, one beeing a table model and one being the important outliner model (domain model within the outliner world).
Since both the tree and the table use the same labels about the items, we would create an abstract view model type to avoid code duplication within the TreeModel and the TableModel.
You noticed something? - Yeah everything about models. Keeping every single model in sync is a burdon.
And content providers?
Well, you know the content provider from above? The table provider would be that easy, too!
ContentProviders are applying a certain view about a domain model. And providing adapters of a domain model is more easier then creating a special purpose model and synchronizing the special purpose model with the domain model.
Conclusion:
-------------
Spring RCP should drop all model adapters and should implement the ContentProvider pattern instead. One solution solves many special problems. I guess some open source code about this should be already available, since I can not imagen that I am the only one favouring the ContentProvider pattern.
So what do you think?
Cheers,
Martin (Kersten)[/code]


Reply With Quote
