Common design patterns are reusable solutions to frequent software design problems. This cheat sheet helps students recognize when a pattern fits a situation and how patterns organize classes, objects, and responsibilities. It is useful for planning programs before coding and for reading larger codebases.
The reference groups patterns into creational, structural, and behavioral categories so students can compare their purposes quickly.
Creational patterns control how objects are created, structural patterns organize how classes and objects connect, and behavioral patterns manage communication and algorithms. Important examples include Singleton for one shared instance, Factory Method for choosing which object to create, Adapter for matching incompatible interfaces, Decorator for adding features, Observer for event updates, and Strategy for swapping algorithms. The main rule is to choose a pattern because it solves a real design problem, not because it makes code look advanced.
Good pattern use usually improves flexibility, readability, and maintainability.
Key Facts
- Creational patterns solve object creation problems, such as Singleton rule: one class controls one shared instance through a private constructor and a public access method.
- Factory Method rule: client code asks a factory method for an object, and the factory decides which subclass or implementation to return.
- Structural patterns solve composition problems, such as Adapter rule: wrap an incompatible object so it matches the interface the client expects.
- Decorator rule: add behavior by wrapping an object in another object with the same interface instead of changing the original class.
- Behavioral patterns solve communication and responsibility problems, such as Observer rule: when one subject changes, all registered observers are notified.
- Strategy rule: define interchangeable algorithms behind a common interface so the client can switch behavior without changing its own code.
- A design pattern is not copied code, but a named design idea that must be adapted to the language, project, and constraints.
- Use a pattern only when it reduces coupling, removes duplication, or makes future changes easier to handle.
Vocabulary
- Design Pattern
- A reusable solution structure for a common software design problem.
- Creational Pattern
- A pattern that controls how objects are created to make construction flexible and safe.
- Structural Pattern
- A pattern that organizes classes and objects into larger working structures.
- Behavioral Pattern
- A pattern that defines how objects communicate, share responsibilities, or choose actions.
- Interface
- A defined set of methods that a class promises to provide, allowing different classes to be used in the same way.
- Coupling
- The level of dependency between parts of a program, where lower coupling usually makes code easier to change.
Common Mistakes to Avoid
- Using a pattern before identifying the problem, which is wrong because patterns should simplify a real design issue rather than add extra classes for no reason.
- Confusing Strategy with Factory Method, which is wrong because Strategy chooses behavior while Factory Method chooses which object type to create.
- Using Singleton as a global variable, which is wrong because unrestricted shared state can make testing harder and create hidden dependencies.
- Changing an existing class when Decorator would work better, which is wrong because modifying the original class can break existing code and violates the open closed principle.
- Treating UML arrows and labels as decoration, which is wrong because they show important relationships such as inheritance, composition, wrapping, and notification.
Practice Questions
- 1 A program has 1 Subject object and 6 Observer objects registered to it. If the Subject changes once and notifies every Observer exactly once, how many update calls are made?
- 2 A drawing app supports 4 shape tools and later adds 3 more. If each tool is implemented as a separate Strategy class, how many Strategy classes are there after the update?
- 3 A media player expects objects with a play(file) method, but an old audio library uses startAudio(fileName). Which pattern should you use to connect them without rewriting the old library?
- 4 A game lets players switch between aggressive, defensive, and stealth enemy behaviors at runtime. Explain why Strategy is a better fit than putting all behavior in one large if else block.
Understanding Common Design Patterns Reference
The useful starting point is not the pattern name. It is the part of the program most likely to change. A checkout program may gain new payment providers.
A game may gain new movement rules. A school app may need to send updates to screens, logs, and alerts. If every new feature requires editing one large class, that class has too many jobs.
Patterns help separate the stable part of a program from the part that varies. This is why diagrams of patterns often show interfaces. An interface gives the rest of the code a dependable promise, even when the object behind it changes.
Object creation has effects beyond the line where an object is made. A shared application settings object, for example, can seem suited to Singleton because many parts of the program need the same settings. Yet global access can hide dependencies.
A method may appear to need no input while silently reading shared state. This makes tests harder because one test can affect another. Students should notice the lifetime and ownership of each object.
Factory Method is especially helpful when the choice depends on a file type, user setting, device, or configuration. The code using the result should work with a general type and should not need a chain of checks for every possible concrete type.
Structural patterns are often about protecting code from awkward boundaries. An Adapter is useful when a library, old module, or web service uses names and method shapes that do not fit the rest of a program. The adapter translates at one clear point, rather than spreading conversion code everywhere.
A Decorator has a different job. It layers optional work around an existing action. A file reader might be wrapped to add buffering, then wrapped again to add encryption.
Since each wrapper should keep the same expected operations, wrappers can be combined. Their order can matter.
Encrypting data before compressing it can produce a different result from compressing it before encrypting it. Too many wrappers can make debugging difficult, so meaningful names and small responsibilities matter.
Behavioral patterns make changing actions easier to control. In an Observer setup, a weather reading could trigger a display update, a saved record, and a warning message. The sender should not need detailed knowledge of those receivers.
Real programs must handle details that simple diagrams omit. Observers may need to unsubscribe when a screen closes. Notifications can arrive in an unexpected order.
One failing observer should not always stop the others. Strategy is a good fit when one task has several valid methods, such as sorting records by name or date, choosing a route, or calculating a game score. Each strategy should be tested with the same inputs so their differences are intentional.
A pattern is earning its place when it makes one future change local and understandable. If it adds layers without a likely source of change, simpler code is usually better.