January 17, 2012

How to implement MVC (Model View Controller) Pattern in Swing

The MVC pattern is the most common pattern when it comes to web framework, but when building a rich client with swing or by using a rich client framework such as, Eclipse Rich Client Platform, Eclipse RCP , or Spring Rich Client Project, Spring RCP or trying to develop a similar platform yourself, thing tends to fast get very complicated. Why is that? Well, first Swing is very low tech. To do even the most simple thing requires quite a lot of lines of code. Another reason is that a lot of people have not taken their time to fully understand the MVC pattern. And maybe last there are a lot of misunderstanding what a view is in the MVC pattern and the Swing model. The Swing model is entire a presentation necessity and therefore only belong to the view.

So hopefully what I will achieve in this blog is to explain the MVC pattern and how to implement it with Swing. What I will not do in this blog is to explain how to use certain Swing components, their are quite a few tutorials out there, e.g. Oracle own Swing Tutorial, http://docs.oracle.com/javase/tutorial/uiswing/.

Last start with explaining the MVC pattern fundamental. Maybe the easiest way to explain MVC is to look at how things work in the web world.


What happens:
  1. The View builds the graphical interface and reacts to user interaction, by redirecting the request to the Controller.
  2. The Controller respond to the request, do logic and sends response to a view.
  3. The View takes these parameters and presents them in a view to the user.
And as you already might have guessed the above request and response parameters is the Model in the MVC pattern.

Before continue I would like to stress a few things extra hard:
  • All graphical components are created and layed out in the view. Nowhere else!
  • The Controller is neutral to whatever graphical user interface technique used! A simple control question is. Think that you must change graphical technique, from example Swing to SVT. Will you controller classes be affected? This question might feel quite theoretical but is a good eye opener if you have successfully separated the view concern from the controller concern.
  • The Model should also be plain old Java object, POJO, and not infected with presentation specific codes. And again check that by asking yourself if you were forced to change presentation technique. How would that affect your model classes?
And a final reminder about the model in the MVC pattern and the model in Swing. The Swing model should not be confused with the model in the MVC pattern. The Swing model is entirely part of the choosen presentation technique, i.e. Swing and belongs only in the view and should not be mixed with the model in the MVC pattern.

The last thing before diving into concrete code is the concern of Object Instances Lifecycle. Now you might start to wonder what that has to do with MVC. And the question is none, but the problem is still real and I think one must adress this with some thinking and strategy, because it is so vital to the application and programmers daily life. And not to mention testability. Which is something I will not go into any deeper in this blog, but I can recommned the FEST test framework. Anyhow which Swing test framework you choose you must before have a clear lifecycle handle of object in your rich client. Otherwise you will end up with untestable code.

So lest start with the View. What does a view do?
  1. Layout the graphical components.
  2. Responds to user interaction (and sends the request to the Controller).
  3. Updates the view (requested from the Controller).
Lets starts with the layout.





Try not to bother about the static component methods, such as frame, etc. they are all methods in a ComponentFactory that do all the Swing plumbing construction. I will later show them in the Appendix.

But our application will certaintly contains several views, so lets we refactor out the main method in a class thats holds the JFrame instance. What we also will do in our frame class is to solve the problem of object lifecycle and dependencies to those. We will create a map that hold all the views and another that holds the controllers. And finally we will inject the instance of the main frame to all views and controllers. In this way, we will have only one instance of all the views and controllers, but also they will be accessable everywhere.





Now lets get back to the View and add code for the user interaction request.



As you can see, it is easy to get instance references to the controller class, but the controller is also used in a type safe way. This approach have several advances compared with external configuration files where you wire views and controllers together through weak string references. What will happen if decide to refactor and change a controller method name?

The view can in the same manner be accessed in the same type safe way. To need for external configuration files, such as XML files.

So this is the basic of MVC. Now look if this holds for more complex GUI. Lets say we want to make a desktop application. Well the layout stays the same, but we need to put theirs panel in internal frame. We could do that in the view, but what happens if requirement changes and these views wants to put in a tabbed panel instead. No lets leave the views intact and instead lets created a decorating view that takes a view of panel as argument.



Then we need to modify our main frame class.










Conclusion
MVC greatly reducing the coupling between seperated classes, but doing right is not always easy.

The complete source code from https://sourceforge.net/projects/swingframework/files/.

3 comments:

Sergei said...

Hello Magnus,
thank you for the very interesting post, it would be really interesting to try it.
Do you have an experience of using your framework in a big projects?
However, I see a potential problem of reusing View components, that is because each your view is bundled to the controller request handler. It means if you need to use 2 instances of the certain View component, but with different logic, you need 2 different controllers or different methods, but it is not possible, as I see. The solution can be to avoid tight relations between View and Controller, i.e. Controller is related to view, but View is independent. It can be done by dispatching events from View to Controller(s), so you can configure via event listeners who is responsible for each view instance.
What do you think?

Thanks.

Кирилл said...

Your code doesn't work .When I run main in MainFrame,I receive :Exception in thread "AWT-EventQueue-0" java.lang.NullPointerException
at se.msc.mvcframework.demo.main.MainFrame.layout(MainFrame.java:26)
at se.msc.mvcframework.AbstractFrame.(AbstractFrame.java:20)
at se.msc.mvcframework.demo.main.MainFrame.(MainFrame.java:12)
at se.msc.mvcframework.demo.main.MainFrame$1.run(MainFrame.java:34)
at java.awt.event.InvocationEvent.dispatch(InvocationEvent.java:251)
at java.awt.EventQueue.dispatchEventImpl(EventQueue.java:733)
at java.awt.EventQueue.access$200(EventQueue.java:103)
at java.awt.EventQueue$3.run(EventQueue.java:694)
at java.awt.EventQueue$3.run(EventQueue.java:692)

niaziakmal khan said...

Programming is combination of intelligent and creative work. Programmers can do anything with code. The entire Programming tutorials that you mention here on this blog are awesome. Beginners Heap also provides latest tutorials of Programming from beginning to advance level.
Be with us to learn programming in new and creative way.