Before we can go into the parts of individual patterns, it
should be mentioned that the GoF categorized the 23 patterns into Creational,
Structural and Behavioral patterns. This helps us to think of patterns among
their peers, whether they instantiate classes for us, arrange the classes into
useful structures for us or help the classes to collaborate at run-time in the
most useful way. This allows us to categorize our thinking broadly.
The GoF break-down each pattern into 4 major parts.
1) As the GoF point out, the design patterns are described
in terms of their name, which allows us to get a quick handle on the general
structure and interaction involved. This is similar to automobiles where,
instead of talking about “the device for cooling water coming from the engine
through the use of the electrically-powered air-turning implement,” we can
simply talk about the “radiator” and “fan.” So the name is very powerful since
it lends itself to a natural association with a mental image of how the pattern
operates and also suggests how the pattern is internally arranged. As they
also point out, the names provide us with a common vocabulary for discussing
the patterns.
2) The problem is similar to a description of the problem for
which an auto part is used to solve. For example, brake-pads are required for
providing the functionality of stopping and radiators are useful for cooling
the engine due to the heat given off. Electrical relays help us to deliver
current in a manner which isolates the switch circuit from the circuit which
actually does work (such as a horn or starter), so that we reduce the risk of
being shocked or setting fire to the car due to an electrical short circuit. Similarly,
the design pattern problem is a scenario that requires a methodical approach in
which the interaction of the classes in the pattern provides functionality that
addresses that problem.
3) The solution helps us to understand how the classes and
objects in the pattern instantiate, compose, interact with and pass messages to
each other in order to solve the problems faced in the particular
circumstances.
Let us revisit the radiator. A radiator usually has pipes
leading hot water to it and cold water out of it, tubes for leading the water
up through fins. These fins provide a greater surface area for the fan to blow
air through in order to cool the hot-water. Not terribly different from the
setup of the CPU-fan/heat-sink in your PC, the arrangement and internal
interactions of the radiator represent a solution to the problem of heat
exchange. In fact, heat transfer systems everywhere have come to use this elegant
arrangement of collaborators; this includes A/Cs, fridges, radiators,
heat-exchangers in Power stations, etc. It just goes to prove that once a
solution to a known problem has been designed in a simple, cost-effective,
recognizable and reproducible way, people will tend to learn and implement it
without fail (hence the adage – “Don’t reinvent the wheel”).
Now just as the radiator:
·
Is an arrangement of smaller parts (which):
·
Carry out responsibilities in sequence (hot water pipe, tubes,
fins, cold-water-pipe)
·
Communicate messages to each other (using water)
·
Activate other components (cause the fan to spin)
·
Instantiate other objects (Check Engine warning)
Similarly, the classes and objects in a design pattern all
have a responsibility for acting out the solution to the problem in the OO
design space.
4) Consequences help us to understand the costs involved in
implementing the pattern so that we can avert as much of the cost as possible
without compromising pattern-safety. Picture a relay that helps us to isolate
high-current circuits from circuits, which the driver may operate through a
switch interface. While the relay is very useful, the fact is that the relay
is an extra circuit to wire, an extra component to fail, more space taken up in
the engine bay, another circuit to maintain and generally represents extra cost
to the owner. The consequences help us to understand how patterns affect the cost
of building the software, the performance impact and how to minimize them, etc.
It also describes how the different trade-offs affect the extensibility we
eventually achieve. Therefore in engineering terms, it shows how we can
optimize the interactions of the classes in the pattern.