One of the design patterns which I find most difficult to get a real grasp of in "real SWING life" is the MVC pattern. I've been through quite a few of the posts at this site which discuss the pattern, but I still do not feel that i have a clear understanding of how to take advantage of the pattern in my (Java SWING) application.
Let's say that I have a JFrame which contains a table, a couple of text fields and a few buttons. I would probably use a TableModel to "bridge" the JTable with an underlying data model. However, all functions responsible for clearing fields, validating fields, locking fields along with button actions would usually go directly in the JFrame. However, doesn't that mix the Controller and View of the pattern?
As far as I can see, I manage to get the MVC pattern "correctly" implemented when looking at the JTable (and the model), but things get muddy when I look at the entire JFrame as a whole.
I'd really like to hear how others go about with regard to this. How do you go about when you need to display a table, a couple of fields and some buttons to a user (using the MVC pattern)?
I don't like the idea of the view being the one that is notified by the model when its data changes. I would delegate that functionality to the controller. In that case, if you change the application logic, you don't need to interfere to the view's code. The view's task is only for the applications components + layout nothing more nothing less. Layouting in swing is already a verbose task, why let it interfere with the applications logic?
My idea of MVC (which I'm currently working with, so far so good) is :
Code Sample
The View :
Like I said creating the view is already verbose so just create your own implementation :)
It's ideal to interface the three for testability purposes. I only provided my implementation of Model and Controller.
The Model :
The Controller :
The Main, where the MVC is setup :
You can create model in a separate, plain Java class, and controller in another.
Then you can have Swing components on top of that.
JTable
would be one of the views (and table model would de facto be part of the view - it would only translate from the "shared model" toJTable
).Whenever the table is edited, its table model tells the "main controller" to update something. However, the controller should know nothing about the table. So the call should look more like:
updateCustomer(customer, newValue)
, notupdateCustomer(row, column, newValue)
.Add a listener (observer) interface for the shared model. Some components (e.g. your table) could implement it directly. Another observer could be the controller that coordinates button availability etc.
That's one way to do it, but of course you can simplify or extend it if its an overkill for your use case.
You can merge the controller with model and have the same class process updates and maintain component availability. You even can make the "shared model" a
TableModel
(though if it's not only used by the table, I would recommend at least providing a friendlier API that doesn't leak table abstractions)On the other hand, you can have complex interfaces for updates (
CustomerUpdateListener
,OrderItemListener
,OrderCancellationListener
) and dedicated controller (or mediator) only for coordination of different views.It depends on how complicated your problem is.
The MVC pattern is a model of how a user interface can be structured. Therefore it defines the 3 elements Model, View, Controller:
Example
When the
Button
is clicked it invokes theActionListener
. TheActionListener
only depends on other models. It uses some models as it's input and others as it's result or output. It's like method arguments and return values. The models notify the ui when they get updated. So there is no need for the controller logic to know the ui component. The model objects don't know the ui. The notification is done by an observer pattern. Thus the model objects only know that there is someone who wants to get notified if the model changes.In java swing there are some components that implement a model and controller as well. E.g. the javax.swing.Action. It implements a ui model (properties: enablement, small icon, name, etc.) and is a controller because it extends ActionListener.
A detailed explanation, example application and source code: https://www.link-intersystems.com/blog/2013/07/20/the-mvc-pattern-implemented-with-java-swing/.
MVC basics in less than 240 lines:
For proper separation, you would typically have a controller class that the Frame class would delegate to. There are various ways to set up the relationships between the classes - you could implement a controller and extend it with your main view class, or use a standalone controller class that the Frame calls when events occur. The view would typically receive events from the controller by implementing a listener interface.
Sometimes one or more parts of the MVC pattern are trivial, or so 'thin' that it adds unnecessary complexity to separate them out. If your controller is full of one line calls, having it in a separate class can end up obfuscating the underlying behaviour. For instance, if the all of the events you are handling are related to a TableModel and are simple add and delete operations you might choose to implement all of the table manipulation functions within that model (as well as the callbacks necessary to display it in the JTable). It's not true MVC, but it avoids adding complexity where it isn't needed.
However you implement it, remember to JavaDoc your classes, methods and packages so that the components and their relationships are properly described!
I have found some interesting articles about implementing MVC Patterns, which might solve your problem.
A book I'd highly recommend to you for MVC in swing would be "Head First Design Patterns" by Freeman and Freeman. They have a highly comprehensive explanation of MVC.
Source (In case you're wondering what a "creamy controller" is, think of an Oreo cookie, with the controller being the creamy center, the view being the top biscuit and the model being the bottom biscuit.)
Um, in case you're interested, you could download a fairly entertaining song about the MVC pattern from here!
One issue you may face with Swing programming involves amalgamating the SwingWorker and EventDispatch thread with the MVC pattern. Depending on your program, your view or controller might have to extend the SwingWorker and override the
doInBackground()
method where resource intensive logic is placed. This can be easily fused with the typical MVC pattern, and is typical of Swing applications.EDIT #1:
Additionally, it is important to consider MVC as a sort of composite of various patterns. For example, your model could be implemented using the Observer pattern (requiring the View to be registered as an observer to the model) while your controller might use the Strategy pattern.
EDIT #2:
I would additionally like to answer specifically your question. You should display your table buttons, etc in the View, which would obviously implement an ActionListener. In your
actionPerformed()
method, you detect the event and send it to a related method in the controller (remember- the view holds a reference to the controller). So when a button is clicked, the event is detected by the view, sent to the controller's method, the controller might directly ask the view to disable the button or something. Next, the controller will interact with and modify the model (which will mostly have getter and setter methods, and some other ones to register and notify observers and so on). As soon as the model is modified, it will call an update on registered observers (this will be the view in your case). Hence, the view will now update itself.