COMP 310

Easy MVC Creation using Anonymous Inner Classes

    Current Home  Java Resources  Eclipse Resources

If you are not already familiar with the Model-View-Controller design pattern please read the linked reference before proceeding.

Trying to make an MVC instantiation is to come up against the age-old problem of CS of making a circular reference:  you can't make the circular reference because when you want to make the reference, you are still building the entity to which you wish to reference and thus cannot reference it.   

In an MVC architecture, the model references its model-to-view adapter, thus the model should take the adapter in its constructor.     Thus the model-to-view adapter must exist before the model, otherwise it cannot be passed as a value to the model's constructor.  But the model-to-view adapter references the view, so therefore the view must exist before the model-to-view adapter.   But the view references its view-to-model adapter, which it should take as an input to its constructor (for the same reasons the model gets its view through its constructor).  But that means that the view-to-model adapter must exist before the view.   But the view-to-model adapter references the model and, to complete the paradox, therefore the model must exist before the view-to-model adapter!

Some folks go an break the symmetry between the model and the view and put a special "setter" method on one of them so that its constructor doesn't take its adapter.   But since the point of the MVC is to decouple the model from the view, one cannot know anything about the other, therefore you can never say whether the model or the view should be the one with the special setter.  Some people put the setter on both the model and the view, making them both ugly for the sake of being able to handle the unknown other.

But there's a much, much better way...

Closures to the Rescue!

The place to fix the problem is not in the model or view classes but in the adapters because those are the custom entities built by the controller for connecting a specific model to a specific view and vice versa.  What we need is to be able to delay the setting of the model and view variables referenced by their respective adapters until after the model and view have been constructed.   That is, let the adapters reference some fields in the controller instance that will, in the end, reference the model and view instances.

Since the system only needs a single instance of each of the adapters, it makes sense to use anonymous inner classes to implement them.   And in our favor, anonymous inner classes follow "lexical scoping" rules, which mean that the code of an anonymous inner class can reference anything within any set of curly braces that encloses it.    In theoretical CS parlance, we say that the anonymous inner class "closes" over all the variables and fields in its scope or conversely, that all the variables and fields outside the anonymous inner class that are in scope form the anonymous inner class's "closure".

The net result is that anonymous inner classes allow us to write adapters that reference fields that have not yet been set to values, in particular, not yet set to reference the model and view instances.

/**
 * MVC Controller for the system
 */
public class Controller {

	// Fields for the adapters to close over:
	private Model model;  // starts off null but will be fine when the constructor is finished.
	private View view;  // starts off null but will be fine when the constructor is finished.
	
	/**
	 * Controller constructor builds the system
	 */
	public Controller() {
	
		// Here the model is shown being constructed first then the view but it could easily be the other way around if needs dictated it. 
	
		// set the model field
		model = new Model( new IModel2ViewAdapter() {
		
			// In the adapter code, one can reference the view field above because it is in scope.
			// It's ok that the view field is currently null because it will be set below.  Just don't start the model yet!
	
			// adapter methods elided
		
		}); 
		
		// set the view field
		view = new View( new IView2ModelAdapter() {
		
			// In the adapter code, one can reference the model field above because it is in scope.
			// The model field is already set here but it doesn't matter if it was or wasn't.   Don't start the view yet!
	
			// adapter methods elided
		
		}); 	
		
		// At this point, both the model and view are instantiated as well as both adapters and both adapters reference non-null model and view fields. 
		
		// NEITHER MODEL NOR VIEW SHOULD BE STARTED YET! 
	}
	
	/**
	 * Start the system
	 */
	public void start() {
		model.start();  // It is usually better to start the model first but not always.
		view.start();	
	}
	
	/**
	 * Launch the application.
	 * @param args Arguments given by the system or command line.
	 */
	public static void main(String[] args) {
		EventQueue.invokeLater(new Runnable() {   // Java specs say that the system must be constructed on the GUI event thread.
			public void run() {
				try {
					Controller controller = new Controller();   // instantiate the system
					controller.start();  // start the system
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		});
	}
}

Note that it is critical that the constructors of the model and view do not start them!    Otherwise, their adapter might get called and end up trying to call methods on an as-yet null field.   This is yet another reason for separating the "start" method out in both the model and the view and thus the controller.

 

 


© 2017 by Stephen Wong