A Survey of Common Design Patterns
The Observer pattern is useful when you need to present data in several different forms at once. The Observer is intended to provide you with a means to define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically. The object containing the data is separated from the objects that display the data and the display objects observe changes in that data.
As the next class diagram shows, there are basically two different types of objects: a Subject and an Observer. The Subject corresponds to the data object whose state you want to track. The Observer is the object that is interested in changes in the Subject object data. To set up the pattern, Subject classes implement a method for registering Observers and for attaching and detaching them from a collection object. In addition, Subjects also implement GetState(...) and SetState(...) methods for the Observer to call. Finally, you also need a notify(...) method to notify all registered Observers when the data has changed. In addition to the Subject, you can also create Subject subclasses to store the Subject's state to satisfy any special requirements of concrete Observers. For Observers, you define a custom abstract Observer class to provide clients with a uniform interface, and subclass the implementation details.
The Prototype is a simple pattern intended to provide you with a way to dynamically select which object to instantiate, and to return a clone of a prototypical object. This pattern is useful in applications that use a graphical toolbox to create instances of subclasses that represent the objects used by an application.
As the following class diagram shows, the pattern consists of an abstract Prototype class that defines a Clone(...) method that all concrete Prototypes implement. The client simply calls the Clone(...) method for the specific concrete Prototype it requires.
The Proxy is intended to provide you with a way to use a surrogate or placeholder to another object in order to control access to it. This pattern is useful for situations where object creation is a time consuming process and can make an application appear sluggish. A proxy object can provide the client with feedback while the object is being created. Proxy can also be used to provide a more sophisticated reference to an object. For example, the proxy object can implement additional logic on the objects behalf (security, remote procedure calls, an so forth).
The next class diagram shows the pattern consists of two types of classes. The Subject is the actual object the client is interested in. An abstract Subject class is defined to provide both the Proxy and the client with a uniform interface to the Actual Subject classes. The Request(...) method is responsible for creating and returning an instance of the Subject. The Proxy overrides this method with its own implementation and manages the reference to the ActualObject class. The Proxy can also implement its own functionality when instantiating the ActualObject class. The client is responsible for selecting and instantiating the Proxy, and some time later, making a call to the Request(...) method. The Proxy responds by returning the actual object.
There are a number of situations in programming where you need to assure that you have only one instance of a class. Print spoolers, window managers, and so forth, are examples of Singletons. The Singleton is intended to provide a way to ensure that a class provides one instance of itself, and to provide a global point of access.
The following class diagram shows the Singleton is a simple pattern. The Singleton class is responsible for instantiating itself and passing that instance on to the client. Therefore, the access modifier for the Singleton constructor must be either private or protected so the client cannot call the constructor itself. The Singleton also provides a method that returns the sole instance of itself to the client. The first time the client requests an instance, the Singleton will create that instance internally and store it as a private member. Each subsequent call from the client will return that instance.
The State pattern is useful when you want to have an object represent the state of an application, and you want to change the state by changing that object. The State pattern is intended to provide a mechanism to allow an object to alter its behavior in response to internal state changes. To the client, it appears as though the object has changed its class. The benefit of the State pattern is that state-specific logic is localized in classes that represent that state.
The next class diagram shows how to implement the State pattern. You define a Context class and an abstract class, State class, which your custom State handlers can implement. The Context class is responsible for calling the appropriate state handlers. The client instantiates the Context class and calls the Request(...) method with the appropriate arguments. The Request(...) method then determines which state handler should handle the request and passes the data to the Handle(...) method. The benefit of the State pattern is deeply nested or complex if statements are localized in the Context class instead of the client. Therefore, when the state of an application has to change in response to use input, the client merely passes this data to the Context object and the appropriate updates to the application state are made.
The Strategy pattern is very useful for situations where you would like to dynamically swap the algorithms used in an application. If you think of an algorithm as a strategy for accomplishing some task, you can begin to imagine ways to use Strategy. Strategy is intended to provide you with a means to define a family of algorithms, encapsulate each one as an object, and make them interchangeable. Strategy lets the algorithms vary independently from clients that use them.
The following class diagram shows the Strategy pattern basically consists of a context class and a set of strategy classes. You define an abstract strategy class that your custom strategy classes can implement. Each strategy object implements the algorithm that makes it unique. The client instantiates the strategy class and passes it as an argument when it calls the constructor of the context class. The client is then able to call methods on the context object and any strategy specific methods as necessary. Because the context creates an instance of the abstract Strategy, the client is effectively using polymorphism to call strategy-specific methods on the context object.
Page 4 of 5