Working out the specifications from the requirements and context
description and working out examples and tests give us a pretty
good idea of what our code is supposed to do. We understand what
it is supposed to do, and perhaps even what is to change in the
future.
Now it's time to code. Ideally, your code should be such that
- any potential, reasonably trained successor can deal with it
- anticipates basic modifications and is therefore organized so
that you can modify the relevant pieces without going thru a
lot of extra stuff. The keyword here is loosely coupled
components; their interaction should be described via
interfaces.
It would be even better if we had evidence that our code
organization has withstood the test of time. That's the point of
handbooks in engineering disciplines. In computer science
object-oriented design patterns play the role of such handbooks.
Patterns
----------------------------------------
The collection of patterns is the result of "software
archaeology", i.e., the careful inspection of millions of lines of
code of (technically) successful projects as well as failures. The
successful projects organize their code in similar ways for
related pieces. The GoF extracted these organizations and
cataloged them.
A pattern consists of several components. The important ones are
- a name, an abstract and terminology for the various pieces
- a description of the problem and its context
- a solution in the form of code organizations
- a discussion of trade-offs.
The pattern handbook should be on every programmer's desk, just
like a thesaurus and a dictionary are on every writer's desk. When
you encounter a problem, look up the abstracts of the patterns in
the book and think whether one of them could solve your problem.
Example
----------------------------------------
Suppose you have some data and some methods for manipulating the
data. Now you want to (1) present the data to users and (2) allow
users to manipulate the data visually.
Concretely:
- Your file system is a collection of data. You can add and
delete files.
File systems come with explorers, but first they came with
text-based tools (shells) that allow programmers and users to
inspect directories and files.
- Your email is collection of data (email addresses, mail message). You
can add, delete, save an address, etc.
Email servers administrate your data and your methods. Email
clients allow you to manipulate the data directly. A button or
a menu in an email client is interpreted as a server-based
method on your data.
Both examples suggest that the collection of data and the
human-interface part are actually independent .. and yes, that's
how we want to organize the code:
- as a model, which is the data and methods for manipulating it
- as a view, which is the user-program interface portion.
Why?
Past experience suggests that we wish to change the view far more
quickly than the model. For example, Windows radically changed the
way users explore the file system, even though the file system
underneath remained the same. Programmers invent new ways to view
mail messages all the time.
People often want more than view for the same model. Many users
want to inspect the file system with a visual organizer (explorer,
finder) but also with a text-based tool (shell, dir,
ls). Similarly, people read their email with an OS-specific tool
and when they are on the road, they may wish to use a Web-based
mail client.
(make a picture)
How do the model and the view work together?
When the model changes, all views need to know.
When the user interacts with the view, the model must be informed.
Or, if the view is disabled, the model should never find out.
Let's see what the GoF book says about this situation. Aha, the
Observer pattern will help.
+--------------+ +--------------+
| Model | | View |
+--------------+ IObserverModel : notify +--------------+
| IObserver l | -----------------------------> | Button |
| State state | | Label |
+--------------+ +--------------+
| void change()| | notify(state)|
| ... | | ... |
+--------------+ +--------------+
^ |
| |
| ----------------+
| | IObserverView : notify
| v
| +--------------+
| interpret | Controller |
+---------------------------- +--------------+
call model actions | ControlState |
+--------------+
| void notify( |
| UserAction)|
| ... |
+--------------+
Also study the code example.
What is ActionListener about? You guessed it: your view is the
model for AWT/Swing's "true view"?