That's a big question. I'll share some thoughts with you I have on this subject and see what comes out of it.
Swing is more Model->View than Model->View->Controller. The problem with Model->View is that typically Swing applications subclass a View object, and that objects becomes both the View and the Controller for that view mushed into one. Overtime in large applications this leads to lots of problems and spaghetti code.
What I've been doing now for several years is to create a separate object called a Controller that doesn't extend any UI classes. It's a plain old object in this respect. This Controller will be in charge of instantiating the top level components for the View, connecting listeners to the view to respond the user, and turning around and making calls onto the model to accomplish work.
The View will subclass Swing. The View is responsible for responding to mouse events, keyboard events, etc. Any sort of Swing specific event is handled in the View. It will also provide high level methods for updating the view that the controller will use to callback to update the UI. Classic swing models are also apart of the View because your choice of components are very much tied to the models you'll use. The View is also in charge of dispatching high level events to the Controller, and the Controller is in charge of responding to those high level events. These events might be UserEvent.ADD, UserEvent.EDIT, AuthenticationEvent.LOG_IN, AuthenticationEvent.LOG_OUT, etc. These events are application events and read more like what a product manager might recognize. The Controller doesn't respond to Mouse, ChangListener, etc. I've actually built my own EventDispatch and Event framework for these because Swing's is so difficult to extend and use effectively. The view works something like:
public void mouseClicked( MouseEvent evt ) {
User u = getUserAt( evt.getPoint() );
dispatch( new UserEvent( UserEvent.EDIT, u ) );
}
In my controller I have simple methods that are wired to those events. Here might be an example of one:
@EventCallback( command = "exit" )
public void exit( AppEvent evt ) {
onExit();
}
@EventCallback(command = "help.about")
public void showAbout(AppEvent evt ) {
audioFinderFrame.showAboutDialog(engine.getLicenseInfo());
}
@EventCallback( command = MediaSourceEvent.START_REFRESH )
public void refreshStarted(final MediaSourceEvent event) {
if( frame != null ) frame.refreshMediaSource( event.getSource(), true );
}
The annotations are an extension I have to add event listener methods quickly to an EventDisptach source. But, the point being is each method on the controller is invoked from the view using high level events. This enables the Controller to be somewhat isolated from how the view is displayed. The Controller's login method doesn't have to worry what components make up the view. He just receives an event and performs the work. The Controller is in charge of the flow of the application.
Since the event system is divorced from the Swing I reuse it in the model layers so the model can dispatch events back to the Controller, and the Controller can relay those changes to the UI.
The model, and Controller are POJOs. The understand events, but that's it. The model is the logic of the application including a level of DAOs, services that might do background jobs, any service layer that talks to the server, and objects most people might say are DTOs. I don't prescribe the logic that DTO should just be simple getter/setter structs. I do allow logic in there because they are the one thing that floats between all layers. Because every layer has access to them it provides a nice place to centralize methods that each layer can reuse. The View, Controller, and Model can access these methods so why not put them in the object that moves between them.
I've also started using Spring for wiring the parts of the model with their dependencies and dependencies the controller has on the model. I've found this model works very well and it's much more pleasant than not using it. It's also nice to have access to technologies like Spring JDBC templates, and JMS templates if I'm using those technologies. But, it's optional.
I never reuse Controllers. Controllers are the most specific thing in your system, and generalities only make them harder to maintain. Generalities do belong in the View and Model because it makes the development easier. So design patterns tend to find themselves on those sides, but seldom in the Controller. Controllers are simple method calls back and forth.
I've found that doing this has made building Swing UIs much easier, and more straight forward. I'm less likely to get into infinite event loops from listening and manipulating two controls at once. I also find it's easier to test and break the system apart because much of my logic exists outside of Swing's grasp. That makes functional testing possible without a huge toolkit trying to simulate mouse clicks, etc.
There's not a lot of code here to illustrate sorry, but hope this helps.