Designing Software  «Prev 

Choosing a Design Pattern

So far in this course, we have seen standard ways for objects of different types to interact: inheritance,
  1. one class containing fields of another classes type,
  2. one class throwing a member of an exception class.

We have one class whose "function" it is to traverse another class and provide some functionality (access to elements) that is not naturally handled within the original class. In other words, we have abstracted one particular functionality out of one class into another. Once we absorb the ideas of object-oriented programming more fully, it becomes really fun to think about objects as each having their own identity, filling a role in a larger system of components, and interacting with each other in particular ways.
Since the idea of an Iterator is fairly useful generally, it has been identified as one of many Design Patterns. Design patterns are an important way of identifying frequently occurring ways in which objects interact, and they help in designing well-structured larger software systems that can be extended easily later. As such, they are an important part of the field of Software Engineering.

Matching Problems with Patterns

This table describes some of the common programming patterns, and suggested design patterns:

Problem Solution Patterns
Your code depends on the names of classes. Changing the class of an object is burdensome because the name of the class is hard-coded in the client program through constructor invocations. Do not use constructors directly in your client classes. Provide an extra level of indirection to the code that invokes the constructor. Abstract Factory
Factory Method
Your code depends on platform idiosyncrasies. #ifdef and conditional compilation only takes you so far.
Even Java's vaunted platform independence has a few weak spots.
Isolate the platform-dependent parts of your program from the platform-independent parts. Abstract Factory
Your code depends on specific methods in specific classes. Separate the request itself from the object and/or method that handles the request. Chain of Responsibility
Your code depends too closely on exactly how an object is implemented. Changing the implementation of the class forces change on the client class. Encapsulation is not airtight. This is more often a problem in C++ with its pointers, pointer arithmetic, and relatively close access to the machine than it is in Java. Often the solution is to wrap an additional layer of interface around the implementation. Abstract Factory
Changing an algorithm requires too many changes in the classes that use it, especially changes that affect the class's interface as well as its implementation. The algorithm should be separated from the class, and moved into a class of its own. Builder
Template Method
Classes are excessively dependent on each other. It's difficult to change one class without changing most or all other classes. Separate classes with additional levels of indirection. Bridge
Chain of Responsibility
Subclassing is too difficult. Use object composition and delegation instead. Bridge
Chain of Responsibility
Composite, Strategy
A class can't be modified, either because you don't have its source code or because too many other classes depend on it. Use object composition to embed an instance of the class inside another class that provides a new interface. Delegate requests to the embedded object. Adaptor