By Jeffrey T. Juday
For every development difficulty you encounter, chances are good that another developer has encountered the same problem. Like most developers, you're pressured to build reliable software fast and meet all requirements. Magic bullets don't exist in software development; instead, you rely on proven practices and methodologies. Among the better software design practices is the application of design patterns. Design patterns allow you to exploit the experience of your predecessors using proven arrangements of objects.
If you've ever used a C# interface, Java interface, or a C++ abstract base class, you've probably been applying design patterns and never knew it. Design patterns incorporate some object-oriented concepts with object arrangements to solve common software development design problems. Reusability and extensibility are the center of the design pattern motivation, much like other object-oriented practices. Design patterns are more than basic data structures such as arrays, linked lists, and binary trees. Like data structures, a design pattern name captures a basic idea. Unlike data structures, design patterns define the behavior of groups of objects.
The C# and Java Frameworks are peppered with design patterns and concepts. Many of the objects you utilize in a framework follow a design pattern. A common design pattern practice is to include the name of the pattern being implemented in the name of the object or objects. If you've utilized objects in a framework that included words such as proxy, adapter, iterator, visitor, and command in the name of the object, most likely you've utilized a design pattern. Understanding design patterns will deepen your understanding of the various C++, C#, and Java libraries and frameworks.
Aside from giving you an under-the-hood understanding of your development tools, applying design patterns will improve your software design, development, and most important, reusability. Design patterns are more than just formulas for software design solutions. An object-oriented approach to software development is the keystone for all design patterns. Understanding the objected-oriented design approach of design patterns is the first step in understanding how design patterns will improve your software development.
Design pattern object-oriented concepts
It's difficult to write Java or C# without some understanding of object-oriented design and development. Understanding design patterns requires understanding basic object-oriented concepts. If you've done development with Java, C++, or C#, you'll be familiar with the following concepts:
- Decomposition is the process of dividing a problem into smaller pieces—in other words, divide and conquer. Break your program into objects, each with specific responsibilities. Reusability is often the result of good decomposition.
- Encapsulation hides the internal construction of an object. Objects are accessed through their interface. So, for instance, encapsulation allows an object to change its internal behavior without changing the way other objects interact with it.
- Polymorphism allows objects with a common base class or interface to be treated in a similar fashion. An object "A" can interact with object "B" without being completely aware of object "B's" true type.
- Inheritance is the concept of extending the behavior of an object. Inheritance has two forms: a concrete class and an abstract base class or interface inheritance. Aside from syntactical differences, the basic difference between the two forms of inheritance is the amount of functionality implemented in the base class. An abstract class implements no functionality in the base class, while a concrete class will have some functionality in the base class.
- Loosely coupled objects are more independent of each other rather than dependent on one another. Loose coupling makes it easier to modify an object with little understanding of the larger system in which the object resides.
Applying the OO concepts
Using the object-oriented concepts outlined above, design patterns solve problems by applying these concepts in the following ways:
- The design pattern philosophy stresses that it is easier to change or add an object implementing an interface rather than anticipate all future functionality of an object. Emphasis is put on the use of abstract base classes, rather than on inheritance from a concrete base class. For a C#, VB.NET, or Java developer, this means interface inheritance.
- Design patterns help promote easier program changes and object reusability. Loosely coupled objects are easier to reuse and change. Keeping objects small and specialized promotes loose coupling.
- Design patterns are built with many small specialized objects. Functional responsibilities are deferred to the object in the system serving the function that is being utilized. Objects delegate responsibility to smaller specialized objects. Objects differing slightly in functionality are composed of smaller objects rather than implementing most of the functionality in a common base class.
Design patterns in practice
In software design, you must often determine what sorts of objects you need in your design. Many times, the objects you need for your solution are not apparent in the requirements. If the requirements exhibit an interaction that is solved by a design pattern, you can apply the pattern.
A design pattern includes a list of common objects and a description of how the objects interrelate. Some common programming dilemmas are outlined below, along with the design pattern for resolving the dilemma. The examples are provided to give you an idea of the type of problems design patterns can solve.
- You've developed a library of routines. Depending on the underlying hardware, the routines must run against a different lower level application programming interface (API). The Cascading Bridge design pattern describes how you can implement classes for dealing with the API variability.
- A portion of a program you've developed monitors changes to a file. You want to notify a number of objects in your program when changes to the file occur. The Observer design pattern describes an observed and observer relationship. It provides guidelines for implementing an observed and observer class.
- You've built a program to spell-check and e-mail messages. You want to support multiple languages in the spell checking, but you want to reuse the e-mailing and text-handling capability of your program. The Strategy design pattern outlines the objects and interfaces you should specify to support the implementation.
Where to go from here
If you're experienced with object-oriented development and design, reading the book Design Patterns: Elements of Reusable Object-Oriented Software, by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides, is probably all you'll need. Familiarity with the design pattern catalog should be your initial focus. You'll be surprised by the number of patterns you're already familiar with. Further understanding design patterns requires practice. Begin to incorporate design patterns in your development and design. You must begin to put design patterns to work to truly understand their value.
Design patterns incorporate some object-oriented concepts, with object arrangements to solve common software development design problems. Applying design patterns to your design and development will improve your object reuse and allow for easier program changes.