One of the things that I implemented with the Sudoku game was a disconnect between the model and the view. I provided a representation of a Sudoku game that knows nothing of user interface. It knows about cells and boxes and numbers; it also knows if any given cell is considered valid. It knows nothing about what colour should be used to draw a cell, how thick the lines should be, or anything else that has anything to do with drawing.
To help with the drawing part, and to avoid having to continually recompute position information for individual cells, I introduced the notion of a CellDrawer
that does know about colours, and line thickness, and such. It also knows–in absolute coordinates–where to draw the cell. This class is part of the user interface code.
I set up the Sudoku board so that it can be observed. Interested parties, like a user interface, can register event listeners that are triggered when a change occurs on the board. I use the listeners consistently. When the user clicks on the board or types a key, the user interface translates that operation into a command that’s passed to the Sudoko board. The command is along the lines of “set the value of the cell at position (5,4) to 7” (position is the relative position of a cell, not a screen co-ordinate). The board makes the necessary modifications and fires an event to inform interested parties of the change. The user interface is one of the interested parties, and when it receives the event it redraws the board. I could have done this a lot simpler: when the user clicks or types a key, change the board and then get the user interface to redraw. Why not just do this? Why all the extra event stuff?
Well… Chris answered this question pretty well. In a few minutes on a plane, Chris added an ECF component to the game: he made the Sudoku game multi-player. He did it without interacting with the user interface, he just worked directly with the model. When the remote user makes a change, a message is sent. When that message is received, the model is modified which causes an event to be triggered resulting in the user interface updating. Pretty cool. And, a fine example of extending a system in a way that the original author had never considered.
I use the event in other places as well. The solver included with the implementation modify the model which then triggers an update of the user interface. The solvers know nothing about the user interface.
At some point, I’ll probably add a couple more views to the game. An obvious view might show some statistics: how many cells are left, how long as the game been going, how many times has a particular cell been changed, etc. This view will also just register itself to receive changed events from the board and update itself whenever those events are triggered. My main user interface will not have to know anything about this new view and so will be totally decoupled; but it will appear to the user to be tightly integrated. Very cool.
This relationship is described by the Observer Pattern. It’s used extensively throughout the Eclipse code (including SWT) and all over the place in Java. Heck, we even used it in (wait for it, Denis…) Smalltalk! It’s a pretty powerful mechanism that may require a little bit of work up front, but sure makes building applications a lot easier.