In object-oriented programming, a design pattern is a solution scheme to a common architectural problem.
The text, Design Patterns: Elements of Reusable Object-Oriented Software by E. Gamma et al., Addison-Wesley 1994, is a famous text that popularized design patterns. Experienced programmers know most or all of the 23 patterns described in that text.
Over the next few weeks, we will study about 8-10 patterns from the Gamma book. (Many people call the text the "Gang of Four" book, because the book has four authors.) The patterns are also documented in Dr. Mizunzo's CIS501 notes.
The Wikipedia page on design patterns has a nice summary of the patterns in the Gamma book.
Design patterns are important to know, not only because they define important "programming tricks", but because they define a "language" that software engineers use when they describe their systems (e.g., "I used an Observer Pattern here to update the views of my model".)
Most design patterns use interfaces and delegates. We should review how these are used before we study any patterns.
Many systems are first designed from classes only. But if several people or teams are coding the system, then the system should be divided into subassemblies --- interfaces let us do that.
When two classes depend on each other (their links form a cycle), the design is flawed. Should the two classes be merged into one? Probably not --- use a delegate to break the cycle.
and say that we wish to "cut" the design into two subassemblies, one holding class C and the other holding D and E. We insert an interface that lists the names of the methods in class D that are called by the code in class C:
Now, the separate assemblies can be coded, compiled, tested, and reused independently.
Also, the interface provides an opportunity to "unplug" class D from the system and replace it with a (better or new-and-improved) alternative, class Dalternative. Interfaces are often introduced into systems where there are several candidates for "plugging into" the system.
Here is a diagram that matches the above story, Steps 1-4: The Manager's requestHelp() method constructs a Helper that the Client calls to doWork(). When the Client is happy, it tells the Helper that it is finished() with it. The Helper calls back the Manager's remove() method, which causes the Helper object to be "deactivated" (and garbage-collected).
The cycle between Manager and Helper is awkward, and it exists only because the Helper must call the remove method at the end of its life. Admittedly, we might eliminate the cycle by making the Client call mgr.remove(h), but the call is not natural for the Client to make.
A better solution for both Client and Manager is to use a delegate declaration so that the Helper is initialized with the method it should call when it is done with its work:
Remember --- a delegate is a kind of "interface" for a single method (and not for an entire class). A delegate is a "simpler" form of interface.