Design Patterns Explained: The Strategy Pattern
This chapter introduces a new case study, which comes from the area of e-commerce (electronic commerce over the Internet). It also begins a solution using the Strategy pattern. I return to this case study in Chapter 16, “The Analysis Matrix.”
- Returns to the problem of new requirements and describes approaches to handling new variations of an existing theme.
- Explains which approach is consistent with the Gang of Four’s philosophy and why.
- Introduces the new case study.
- Describes the Strategy pattern and shows how it handles a new requirement in the case study.
- Describes the key features of the Strategy pattern.
An Approach to Handling New Requirements
Many times in life and many times in software applications, you have to make choices about the general approach to performing a task or solving a problem. Most of us have learned that taking the easiest route in the short run can lead to serious complications in the long run. For example, none of us would ignore oil changes for our car beyond a certain point. True, I may not change the oil every 3,000 miles, but I also do not wait until 30,000 miles before changing the oil. (If I did so, there would be no need to change the oil any more: The car would not work!) Or consider the “desktop filing system”—the technique of using the top of the desk as a filing cabinet. It works well in the short run, but in the long run, as the piles grow, it becomes tough to find anything. Disaster often comes in the long run from suboptimal decisions made in the short run.
Unfortunately, when it comes to software development, many people have not learned these lessons yet. Many projects are only concerned with handling immediate, pressing needs, without concern for future maintenance. There are several reasons projects tend to ignore long-term issues such as ease of maintenance or ability to change. Common excuses include the following:
- We really can’t figure out how the new requirements are going to change.
- If we try to see how things will change, we’ll stay in analysis forever.
- If we try to write our software so we can add new functionality to it, we’ll stay in design forever.
- We don’t have the budget to do so.
- The customer is breathing down my neck to get this implemented right now. I don’t have time to think.
- I’ll get to it later.
There seem to be only two choices:
- Overanalyze or overdesign—I like to call this “paralysis by analysis,” or
- Just jump in, write the code without concern for long-term issues, and then get on another project before this short-sightedness causes too many problems. I like to call this “abandon (by) ship (date)!”
Because management is under pressure to deliver and not to maintain, maybe these results are not surprising. But take a (quick!) moment to reflect. Could there be a third way? Could it be that my basic assumptions and belief systems keep me from being seeing alternatives? In this case, the belief is that it is more costly to design for change than to design without worrying about change.
But this belief is often false. In fact, the opposite is often true: Stepping back to consider how a system might change over time often results in a better design becoming apparent. And this often takes less time than the standard, “hurry-up-and-get-it-done-now” approach. Better quality code is easier to read, test, and modify. These factors compensate for any additional time it might take to do it right.
The following case study is a great illustration of the “design-with-change-in-mind” approach. Note that I am not trying to anticipate the exact nature of the change. Instead, I am assuming that change will happen and I am trying to anticipate where those changes will occur. This approach is based on the principles described in the Gang of Four book:
- Program to an interface, not an implementation.”1
- Favor object [aggregation] over class inheritance.”2
- Consider what should be variable in your design. This approach is the opposite of focusing on the cause of redesign. Instead of considering what might force a change to a design, consider what you want to be able to change without redesign. The focus here is on encapsulating the concept that varies, a theme of many design patterns.”3
Here is what I suggest: When faced with modifying code to handle a new requirement, you should at least consider following these strategies. If following these strategies will not cost significantly more to design and implement, then use them. You can expect a long-term benefit from doing so, with only a modest short-term cost (if any).
I am not proposing to follow these strategies blindly, however. I can test the value of an alternative design by examining how well it conforms to the good principles of object-oriented design. This is essentially the same approach I use in deriving the Bridge pattern in Chapter 10, “The Bridge Pattern.” In that chapter, I measure the quality of alternative designs by seeing which one followed object-oriented principles the best.