views:

1307

answers:

4

I'm developing a java swing application that will have several subsystems. For all intents and purposes, let's assume that I am making an internet chat program with a random additional piece of functionality. That functionality will be... a scheduler where you can set a time and get a reminder at that time, as well as notify everyone on your friend list that you got a reminder.

It makes sense to organize this functionality into three classes: a GUI, a ChatManager, and a Scheduler. These classes would do the following:

GUI - Define all of the swing components and events
ChatManager - Create a chat connection, send and receive messages, manage friend list
Scheduler - Monitor system time, send notifications, store a file to remember events between sessions

For the program to work, each of these classes must be capable of communicating with the other two. The GUI needs to tell the ChatManager when to send a message and tell the Scheduler when to start monitoring. The ChatManager needs to display messages on the GUI when they're received, and finally, the Scheduler needs to both notify the GUI when it's finished, and send a status update or whatever to the ChatManager.

Of course, the classes as described here are all pretty simple, and it might not be a bad idea to just let them communicate with each other directly. However, for the sake of this question, let's assume the interactions are much more complex.

For example, let's say we can register a particular event with the scheduler instead of a particular time. When sending a message, I went to send it to the user, store it in a log file, create an event object and pass it to the scheduler, and handle any exceptions that might be thrown along the way.

When communication becomes this complex, it becomes difficult to maintain your code if communication with these classes can be happening in many different places. If I were to refactor the ChatManager, for example, I might also need to make significant chaneges to both the GUI and Scheduler (and whatever else, if I introduce something new). This makes the code difficult to maintain and makes us sleep-deprived programmers more likely to introduce bugs when making changes.

The solution that initially seemed to make the most sense is to use the mediator design pattern. The idea is that none of these three main classes are directly aware of each other, and instead, each is aware of a mediator class. The mediator class, in turn, defines methods that handle communication between the three classes. So, for example, the GUI would call the sendMessage() method in the mediator class, and the mediator would handle everything that needed to happen. Ultimately, this decouples the three main classes, and any changes to one of them would likely only result in changes to the mediator.

However, this introduces two main problems, which ultimately resulted in me coming here to seek feedback. They are as follows:

Problems

  1. Many tasks will need to update the GUI, but the Mediator isn't aware of the components. - Suppose the user starts the program and enters their username/password and clicks login to login to the chat server. While logging in, you want to report the login process by displaying text on the login screen, such as "Connecting...", "Logging in...", or "Error". If you define the login method in the Mediator class, the only way to display these notifications is to create a public method in the GUI class that updates the correct JLabel. Eventually, the GUI class would need a very large amount of methods for updating its components, such as displaying a message from a particular user, updating your friend list when a user logs on/off, and so on. Also, you'd have to expect that these GUI updates could randomly happen at any time. Is that okay?

  2. The Swing Event Dispatch Thread. You'll mostly be calling mediator methods from component ActionListeners, which execute on the EDT. However, you don't want to send messages or read/write files on the EDT or your GUI will become unresponsive. Thus, would it be a good idea to have a SingleThreadExecutor available in the mediator object, with every method in the mediator object defining a new runnable that it can submit to the executor thread? Also, updating GUI components has to occur on the EDT, but that Executor thread will be calling the methods to update the GUI components. Ergo, every public method in the GUI class would have to submit itself to the EDT for execution. Is that necessary?

To me, it seems like a lot of work to have a method in the GUI class to update every component that somehow communicates with the outside, with each of those methods having the additional overheard of checking if it's on the EDT, and adding itself to the EDT otherwise. In addition, every public method in the Mediator class would have to do something similar, either adding Runnable code to the Mediator thread or launching a worker thread.

Overall, it seems like it is almost as much work to maintain the application with the Mediator pattern than to maintain the application without it. So, in this example, what would you do different, if anything?

A: 

Here, a partial answer to you design questions...

It looks like you want to have loose coupling between your components. In your case, I would use the mediator as a message dispatcher to the GUI.

The ChatManager and the Scheduler would generate UpdateUIMessage.

And I would write my GUI that way

public class MyView {

    public void handleUpdateMessage(final UpdateUIMessage msg){
     Runnable doRun = new Runnable(){
      public void run(){
       handleMessageOnEventDispatcherThread(msg);
      }
     };
     if(SwingUtilities.isEventDispatcherThread()){
      doRun.run();
     } else {
      SwingUtilities.invokeLater(doRun);
     }
    }
}

So you have only one public method on your GUI, which handles all the EdT stuff.

If you want to have a loose coupling between the GUI and the other components (meaning : you do not want the GUI to know all the API of the other components), the GuiController could also publish ActionMessage (on a specific Thread?), which would be dispatched by the mediator to the other components.

Hope it helps.

Laurent K
+1  A: 
  1. Your GUI classes will end up with many methods to keep it up to date and that is fine. If it worries you there is always the option of breaking up the GUI into sub GUIs each with a different functionality or a small set of related functionality. The number of methods will obviously not change, but it will be more organised, coherent and decoupled.

  2. Instead of having every method in your GUI create a Runnable and use SwingUtilities.invokeLater to put that update on the EDT I'd advise you to try out another solution. For my personal projects I use The Swing Application Framework (JSR296) which has some convenient Task classes for launching background jobs and then the succeed method is automatically on the EDT thread. If you cannot use this you should try and create your own similar framework for background jobs.

willcodejavaforfood
Splitting the GUI into multiple classes and having the mediator communicate with a GUI controller sounds like a good idea. It doesn't reduce the number of methods, but it actually makes it a lot more organized in a lot of ways. The SwingWorker API (included in JDK6, I believe), offers a convenient interface for launching background threads and executing methods on the EDT either during or after the thread's lifetime. Having the mediator use these can simply notifying the GUI when certain long-running tasks are finished.
@Jack - exactly :)
willcodejavaforfood
A: 

Well, I will change the world you are working with. You have 3 classes and each of them is just observer of the chat-world. The MVC is the way how to deal with your problem. You had to create Model for your world, in this case chat program. This model will store data, chat queue, friend list and keep eye on consistency and notify everybody interested about changes. Also, there will be several observers which are interested in state of world and are reflecting its state to user and server. The GUI is bringing visualization to friends-list and message queue and reacts on their changes. The Scheduler is looking about changes in scheduled tasks and update model with their results. The ChatManager will be better doing its job in several classes like SessionManager, MessageDispatcher, MessageAcceptor etc. You have 3 classes with empty center. Create center and connect them together using this center and Observer Pattern. Then each class will deal only with one class and only with interesting events. One GUI class is bad idea. Divide to more subclasses representing logical group (view of model). This is the way how to conquer your UI.

Rastislav Komara
MVC is a great pattern. In particular, I think it would be a wise design choice when handling multiple GUI classes. However, the GUI isn't just observing the chat, it could also be observing the scheduler, and any number of other classes. In addition, those classes are observing the GUI, and each other. That's a lot of different kinds of observers you'd have to create. You could also take a command approach and encapsulate all events in a generic object, but parsing that could take a big toll on performance.
Well, I see you did not understand my answer. The real power is making model which hold state of the world. And then observers for this model only and controllers which modify model state. You lower your interaction between classes to Controller/Observer -> Model. There is no need to create interactions between C1/O1 <-> C2/O2.
Rastislav Komara
A: 

You might want to look at a project that originally started as a MVC framework for Flex development. PureMVC has been ported to many programming languages meanwhile. There is a Java port as well. Though it is only in a alpha status as of writing this!

martin.ahrer