Design patterns help you write good software. How can you master all 23+ of them? You are probably better of focusing on the underlying truth: the design principles.
The book “Design Patterns: Elements of Reusable Object-Oriented Software” is a classic and a must-read (see post). When I first came across the book, I read about all those 23 fantastic patterns. They were all different and applicable in different situations. As a computer scientist, I hate special cases, so I wanted to see some kind underlying truth. At the time, I did not see a pattern (ironic, huh? :).
The book “Implementing Lean Software Development” (see post) makes the following definitions:
- “Principles are underlying truths that don’t change over time […]”
- “[…] practices are the application of principles to a particular situation”
If the design patterns are 23 different applications of some underlying truth, this will make them object-oriented software development practices. Then what are the principles of object-oriented software development?
Here are my favorites among the design principles:
- Decoupling: Strive for loosely coupled designs between objects that interact.
- Open/Closed Principle: Classes should be open for extension, but closed for modification (= classes should be easy to extend without needing to change them).
- Abstraction: Depend on abstractions, do not depend on concrete classes.
- Single Responsibility: A class should have only one reason to change.
- DRY (Don’t Repeat Yourself): Store information in a single place, do not scatter it throughout your code.
To exemplify, let’s look at design patterns that support some of the above principles. Two of the patterns that are closely related to Decoupling is Observer and Factory Method. Observer lets a class notify other classes without knowing about them. Factory Method lets one class create objects without knowing which type they are. Not knowing about each other typically favors a loosely coupled design.
Two of the patterns that support the Open/Closed Principle is Strategy and Template Method. Strategy lets you vary the behavior of an object as if the type was not fixed at compile-time. You determine the behavior by supplying a strategy object e.g. during construction. Template Method will let you implement parts of an algorithm. Typically, you subclass the algorithm and implement specialization in the subclass. Both let you change the behavior without changing the code.
If you adhere to the object-oriented principles above, design patterns come up naturally. I think this is also the best way to learn how to apply design patterns. Instead of actively looking for places where your design patterns could fit, use the principles and the patterns will follow.
Some of the design principles are hard to match with any of the design patterns. For example, Abstraction is typically something expressed in the domain language of the problem you’re trying to solve. Thus, it helps you to write code that relates better to your domain. The same goes for Single Responsibility, since the reason for change is domain specific. If you look at all design principles, it is clear that they are themselves special cases that can be divided into groups of related responsibility. It makes you wonder what is the underlying truth of the design principles?