Introduction to design patterns, Part 1: Design pattern history and classification

Get an overview of design patterns, then use what you've learned to evaluate whether the Composite pattern is a good choice for a particular Java use case

1 2 Page 2
Page 2 of 2

Structural patterns

A structural pattern teaches us how to compose classes and objects to form larger structures. A structural class pattern relies on inheritance to compose a resulting interface or implementation (for example, multiple inheritance mixes two or more classes into one class). A structural object pattern composes various objects to obtain new functionality; the Composite pattern is one example of this approach.

  • Adapter: Converts a class's interface into another interface that clients expect. An adapter lets classes work together that otherwise couldn't due to incompatible interfaces. It does so by providing its interface to clients while using the original class interfaces internally. Adapter is also known as the Wrapper pattern.
  • Bridge: Decouples an abstraction from its implementation, which lets the two vary independently. The bridge uses encapsulation, aggregation, and can also use inheritance to separate responsibilities into different classes.
  • Composite: Composes objects into tree structures that represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
  • Decorator: Dynamically attaches additional responsibilities to an object while maintaining the same interface. Decorators provide a flexible alternative to subclassing for extending functionality.
  • Facade: Provides a unified interface to a set of interfaces in a subsystem. Facade defines a higher-level interface that makes the subsystem easier to use. Facades can wrap poorly-designed APIs in a single well-defined API.
  • Flyweight: Uses sharing to support large numbers of similar objects efficiently. A flyweight is an object that minimizes memory use by sharing as much data as possible with other similar objects. It offers a way to use objects in large numbers when a simple repeated representation would result in an unacceptable amount of allocated memory.
  • Front controller: Provides a centralized entry point for handling requests. This pattern relates to the design of Web applications.
  • Module: Implements the concept of software modules, defined by modular programming, in a programming language that does not support or only partly supports modules.
  • Proxy: Provides a surrogate or placeholder object for another object. This proxy controls access to the other object.

Behavioral patterns

Behavioral patterns focus on algorithms and the assignment of responsibilities between objects. They address object or class patterns as well as the communication patterns between them. A behavioral class pattern uses inheritance to distribute behavior among classes. In contrast, a behavioral object pattern uses object composition.

  • Blackboard: This is a generalization of the Observer pattern that supports multiple readers and writers. The Blackboard pattern communicates information systemwide.
  • Chain of responsibility: Avoids coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. This pattern chains together receiving objects and passes a request along the chain until an object handles the request.
  • Command: Uses an object to encapsulate all information needed to call a method at a later time. This information includes the method name, the object that owns the method, and values for the method parameters. A client instantiates the command object and provides the information required to call the method. The invoker decides when the method should be called. Finally, the receiver is an instance of the class that contains the method's code.
  • Interpreter: Given a language, defines a representation for its grammar along with an interpreter that uses the representation to interpret sentences in the language.
  • Iterator: Enables developers to access the elements of an aggregate object sequentially without exposing its underlying representation.
  • Mediator: Defines an object that encapsulates how a set of objects interact. Mediator promotes loose coupling by keeping objects from referring to each other explicitly, and it lets you vary their interaction independently.
  • Memento: Without violating encapsulation, captures and externalizes an object's internal state so that the object can be subsequently restored to this state.
  • Null Object: Avoids null references by providing a default object.
  • Observer: Defines a one-to-many dependency between objects where a state change in one object results in all of its dependents being notified and updated automatically. Observer is also known as the Publish-subscribe pattern.
  • Servant: Defines functionality for a group of classes without defining that functionality in each of those classes. A servant is a class whose instance (or the class itself) provides methods that perform a desired service, while objects for which (or with whom) the servant does something are passed to servant methods as parameters.
  • Specification: Recombines business rules by chaining the business rules together using Boolean logic.
  • State: Allows an object to alter its behavior when its internal state changes. The object will appear to change its class.
  • Strategy: Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
  • Template method: Defines the skeleton of an algorithm in an operation, deferring some steps to subclasses. Template method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure.
  • Visitor: Represents an operation to be performed on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.

Concurrency patterns

Finally, a concurrency pattern addresses some aspect of multithreaded programming. One well-known pattern in this category is Producer-consumer, in which a producer thread stores an item in a shared buffer and a consumer thread retrieves this item. The producer thread must not store another item in this buffer until the previous item has been consumed, and the consumer thread must not consume a non-existent item.

  • Active object: Decouples method execution from method invocation for objects in which each object resides in its own thread of control. The goal is to introduce concurrency, by using asynchronous method invocation and a scheduler for handling requests
  • Balking: Only executes an action on an object when the object is in a particular state. For example, an object reads a file and provides methods to access file content. When the file is not open and an attempt is made to call a method to access content, the object "balks" at the request.
  • Binding properties: Combines multiple observers to force properties in different objects to be synchronized or coordinated in some way.
  • Double-checked locking: Reduces the overhead of acquiring a lock by first testing the locking criterion (the "lock hint") without actually acquiring the lock. The lock is acquired only when the locking criterion check indicates that locking is required.
  • Event-based asynchronous: A concurrency pattern for the asynchronous invocation of an object's potentially long-running methods.
  • Guarded suspension: Manages operations that require both a lock to be acquired and a precondition to be satisfied before the operation can be executed.
  • Lock: A mechanism to temporarily make some aspect of an object unmodifiable or to suppress unneeded update notifications.
  • Messaging design pattern (MDP): Allows the interchange of information (that is, messages) between components and applications.
  • Monitor object: An object whose methods are subject to mutual exclusion, thus preventing multiple objects from erroneously trying to use it at the same time.
  • Reactor: An event-handling pattern for handling service requests delivered concurrently to a service handler by one or more inputs. The service handler then demultiplexes the incoming requests and dispatches them synchronously to the associated request handlers.
  • Read-write lock: A lock that allows concurrent read access to an object, but requires exclusive access for write operations.
  • Scheduler: A concurrency pattern used to explicitly control when threads may execute single-threaded code; for example, multiple threads wanting to write data to the same file.
  • Thread pool: A concurrency pattern in which a number of threads are created to perform various tasks, which are usually organized in a queue. Typically, there are many more tasks than threads. Thread Pool can be considered a special case of the Object Pool creational pattern.
  • Thread-specific storage: A concurrency pattern in which static or global memory is localized to a thread. Each thread has its own copy of this memory.

The previous lists describe many commonly used (and some less commonly used) software design patterns and are not exhaustive. See the end of this article for further reading.

Conclusion to Part 1

Design Patterns: Elements of Reusable Object-Oriented Software significantly impacted the field of software design patterns. In Part 2, I'll present a helpful way to learn the foundational design patterns presented by the Gang of Four authors, revisit the book's Visitor pattern from a Java technology perspective, and discuss some possible downsides of the GoF patterns and of using software design patterns generally. In the meantime, be sure to check the resource links below for a listing of design pattern tutorials on JavaWorld and elsewhere.

Learn more about design patterns in software development

David Geary's Java design patterns series is an excellent first stop for learning about some of the Gang of Four patterns mentioned in this article:

Allen Holub wrote about several important concurrency patterns and other design techniques for his Java toolbox series, "Programming Java in the real world":

Brian Goetz's two JavaWorld articles about double-checked locking are essential reading for anyone inclined to put too much faith in an out-of-the-box solution:

Design patterns are discussed in JavaWorld's Java 101, Java tips and Java Q&A series:

Some patterns have become more important with time:

Others have stood the test of time:

Additional resources for learning about design patterns:

1 2 Page 2
Page 2 of 2