When the Gang of Four published its famous book on design patterns, it ushered a rage among serious developers to reconsider and even rewrite their programs using the newly named and illustrated techniques. While I maintained my usual skepticism about all things suddenly popular, I liked the ability to refer to a series of programming constructs with a single word. Today, if someone says "Proxy pattern," the phrase conveys a specific series of actions, done in a certain way, to achieve a specific goal. And by presenting 23 such patterns (a number that has struck me at various times as too few and too many), the GoF helped developers communicate implementation tactics simply. This linguistic aid also locked into the language terms that we now use routinely, but were little-used before the book except in specialized domains: singleton, iterator, decorator, and proxy object.
While the GoF book did a good job of explaining what the patterns were, it was far less helpful in explaining where and when to use them. Subsequent books (in order of my recommendation) emerged during the next decade to fill that gap: Joshua Kerievsky's Refactoring to Patterns, our columnist Allen Holub's Holub on Patterns, and Shalloway and Trott's Design Patterns Explained. For beginners, Head First Design Patterns from O'Reilly is a pleasant, somewhat goofy alternative.
The problem with the GoF book and other sources of information is that they don't sufficiently distinguish the important patterns from the ones you can safely leave behind. But now that we have 15 years of experience with these techniques, we have the benefit of hindsight and can see that some patterns are rarely used. (Let's face it, how many times are you likely to write an interpreter and consult the Interpreter pattern when you do so?)
There will be some quibbling among readers, I expect, but I think it's safe to say that the following patterns can be considered very much secondary: Bridge, Chain of Responsibility, Interpreter, Mediator, Memento, and Prototype. A pattern that is popular but whose use, in my opinion, should be restricted is the Singleton. It's a creational pattern that allows the developer to create one and only one instance of an object. It's most often condemned because the Singleton is generally implemented as a global variable, which is a practice long frowned upon. In my own practice, it's not so much the global part that's a problem, as it is that Singletons wreak havoc on testing. When you can build only one instance of an object, and so are denied access to a constructor, you find yourself constantly twisting your tests to get around the object's constraints. Eventually, you come to the inescapable conclusion: It is easier to create the items as a plain old object and limit yourself to creating one instance by pure discipline.
Another problem with most instruction on patterns is that the books read like catalogs of ready-made solutions that are illustrated using trivial examples. The result is that many developers and designers who would be inclined to favor patterns get lost in them. They don't fully understand them and, as in my case, tend not to see opportunities to use them. (Kerievsky's book is particularly useful with this problem.)
I've long felt it would be a lot easier to learn patterns in groups, not by function (which is the common way), but by usefulness. The most useful should be known intimately, the lesser used should be known well enough to be able to discuss them (even if implementation requires a quick refresher), and a final tier of patterns such as those I listed earlier can be postponed until relevant (although not forgotten completely).
In the first group of the most useful, I'd place Adapter, Command, Decorator, Façade, Factory/Abstract Factory, Observer, and Strategy. Your mileage may vary and you might include other patterns, but I doubt many readers would exclude any of these. I'd move the patterns not mentioned so far into the second group. And I'd move the least used patterns plus Singleton and Iterator into the last group. Singleton for completion's sake, since the pattern comes up frequently in writing and conversation. I'd put Iterator in the last group, too, because despite its constant use, most developers never have to actually implement iteration code. (Such is the widespread availability of good collections libraries.)
I expect that the greatest push-back will come from true believers who feel that good developers should know all 23 patterns thoroughly. I plain disagree. Interpreter is the perfect example of why all patterns need not be learned equally well. And even the deepest pattern aficionado, I trust, will agree that learning the most common patterns first makes a lot of sense.