- Published on
- · July 16, 2026
Design Patterns: what they are and how to apply them in software
- Blog

- Henrico Piubello
- Henrico Piubello
- IT Specialist - Grupo Voitto
IT Specialist - Grupo Voitto
- What are Design Patterns?
- What are the categories of Design Patterns?
- Which patterns are most used in practice?
- Do Design Patterns still matter with modern frameworks?
- When to use (and when to avoid) Design Patterns?
- How to learn Design Patterns efficiently?
- Conclusion
Design Patterns (design patterns) are reusable, tested solutions to recurring problems in software design. Instead of reinventing the wheel, you apply a proven model — adapted to your context — and gain a shared vocabulary, more predictable code, and systems that are easier to maintain.
What are Design Patterns?
Design Patterns are formal descriptions of solutions to common object-oriented design problems: each pattern names the problem, the class structure that solves it, the consequences of the choice, and usage examples. They were popularized in 1994 by the book Design Patterns: Elements of Reusable Object-Oriented Software, written by Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides — the "Gang of Four" (GoF) — which cataloged 23 patterns.
The essential point: a pattern is not a piece of ready-made code to copy and paste. It is a model of relationships between classes and objects that you implement in your language, in your domain. Two systems can use the same Observer pattern with completely different code.
The most underrated benefit is communication. Saying "this module exposes a Facade" or "I replaced the giant if with Strategy" conveys an entire architecture decision in one sentence — the same role the clean code principles play in readability, patterns play in design.
What are the categories of Design Patterns?
The 23 GoF patterns are divided into three categories, according to the type of problem they solve: object creation, composition of structures, and communication between objects.
| Category | Problem it solves | Best-known patterns |
|---|---|---|
| Creational | How to create objects flexibly and decoupled | Singleton, Factory Method, Abstract Factory, Builder, Prototype |
| Structural | How to compose classes and objects into larger structures | Adapter, Decorator, Facade, Composite, Proxy, Bridge |
| Behavioral | How objects interact and split responsibilities | Observer, Strategy, Command, Iterator, State, Chain of Responsibility |
The creational ones decouple the code from the concrete way of instantiating objects — useful when creation is expensive, conditional, or needs to be controlled. The structural ones organize relationships: they adapt incompatible interfaces, add responsibilities without inheritance, simplify complex subsystems. The behavioral ones define communication flows: who notifies whom, how algorithms are swapped at runtime, how requests become objects.
Which patterns are most used in practice?
In day-to-day practice, half a dozen patterns solve the vast majority of problems — and you probably already use them without naming them:
- Singleton (creational): ensures a single instance of a class with global access — typical in database connections, loggers, and configurations. Use sparingly: in excess it becomes disguised global state and makes testing harder.
- Factory Method (creational): delegates object creation to a method that decides which concrete class to instantiate. It is the basis of dependency injection in frameworks like Spring and NestJS.
- Adapter (structural): converts the interface of an existing class into the interface the client expects — the pattern behind every third-party SDK wrapper.
- Decorator (structural): adds behavior to an object without changing its class, by wrapping it. Middlewares and HTTP request interceptors follow this idea.
- Observer (behavioral): "subscribed" objects are notified when another''s state changes. It is the heart of event systems, from the browser DOM to React and Vue reactivity.
- Strategy (behavioral): encapsulates interchangeable algorithms behind a single interface — the classic antidote to chains of
if/elsethat choose "how to calculate" something (shipping, discount, sorting).
Practical example: a checkout that accepts Pix, card, and bank slip. Without a pattern, a switch grows with every new payment method. With Strategy, each method becomes a class with a process() method, and the checkout receives the ready-made strategy — adding a new method does not touch existing code, respecting the open/closed principle.
Do Design Patterns still matter with modern frameworks?
Yes — the patterns did not disappear, they were absorbed into the tools. Modern frameworks are collections of packaged patterns: the dependency injection container combines Factory and Singleton; routing with middlewares is Chain of Responsibility; state hooks implement Observer; ORMs use Proxy and Unit of Work.
Knowing the patterns changes your relationship with the framework: you stop memorizing APIs and start recognizing the intent behind them — which accelerates learning any new stack and helps you decide when to step off the happy path. In distributed architectures, the same principles reappear at a larger scale: an API Gateway is a Facade of microservices, and event queues are Observer between systems.
When to use (and when to avoid) Design Patterns?
Use a pattern when the problem it solves has already shown up in the code; avoid it when the motivation is only "to follow best practices." Patterns have a cost: each one adds indirection and extra classes. The right question is not "which pattern can I use here?", but "what problem am I having — and is there a pattern for it?".
Signs a pattern will help:
- The same
if/elseover "types" repeats in several places (Strategy or polymorphism). - Creating an object requires knowing too many implementation details (Factory or Builder).
- A state change needs to be reflected in several places (Observer).
- You need to integrate a library whose interface does not match your code (Adapter).
Signs of overengineering: abstractions with a single implementation, factories that always create the same class, layers that only forward calls. In those cases, direct and simple code wins — refactoring to a pattern later is cheaper than carrying speculative complexity from the start.
How to learn Design Patterns efficiently?
The most efficient way to learn is to connect each pattern to a problem you have already lived, in three steps:
- Study the problem before the structure. For each pattern, formulate in one sentence the pain it solves ("state changes need to notify interested parties" → Observer).
- Find the patterns in the code you already use. Open the source of your favorite framework or identify patterns in your day-to-day libraries — it is the best catalog of real examples.
- Refactor your own code. Take an extensive
switchor a God class from a personal project and apply Strategy or Facade. Getting the dose wrong in study code teaches more than any reading — and a solid base of programming logic makes the process natural.
Recommended resources: the GoF book (formal reference), Head First Design Patterns (didactic), and the Refactoring.Guru site, which illustrates the 23 patterns with examples in several languages.
Conclusion
Design Patterns are the shared vocabulary of software engineering: solutions tested for decades to problems every object-oriented system faces. Mastering the three categories — creational, structural, and behavioral — and recognizing the six or seven most frequent patterns makes your code more predictable, your architecture conversations more precise, and your framework learning faster. But the criterion is as important as the catalog: a good pattern is one that solves a real problem in your code, not one that decorates the diagram. Start simple, identify the pain, and only then apply the pattern — that is the essence of robust and scalable architecture.
## faq
Frequently asked questions
What are Design Patterns in programming?
Design Patterns are generic, tested, and documented solutions to problems that show up repeatedly in object-oriented software design. They are not ready-made code to copy, but models of structure and interaction between classes that you adapt to your context.
What are the three categories of Design Patterns?
Creational, which deal with object creation (Singleton, Factory Method, Builder); structural, which organize the composition of classes and objects (Adapter, Decorator, Facade); and behavioral, which define how objects interact and distribute responsibilities (Observer, Strategy, Command).
Do I need to memorize all 23 GoF patterns?
No. In practice, a subset solves most cases: Factory Method, Singleton, Adapter, Decorator, Observer, and Strategy. What matters is recognizing the problem each pattern solves to know when (and whether) to apply it — memorizing the structure without understanding the problem leads to misuse.
Do Design Patterns still make sense with modern frameworks?
Yes — they are embedded in the frameworks themselves. React uses Observer in its state system, Spring and NestJS dependency injection uses Factory and Singleton, and Express middlewares follow Chain of Responsibility. Knowing the patterns helps you understand and extend these tools.
When NOT to use a Design Pattern?
When the problem does not exist yet. Applying patterns preventively, "because it''s best practice," adds layers of abstraction that make reading and maintenance harder — the so-called overengineering. Start simple and introduce the pattern when the pain it solves actually shows up in the code.
Topics in this article
## continue lendo
Artigos relacionados
Keep browsing
Previous article

Technology salaries in Brazil: a guide by role and level
How much do people who work in tech earn in Brazil? See salary ranges by role and seniority, the factors that matter, and how to negotiate better.
Read moreNext article

Platform Engineering: what it is and how it accelerates dev teams
Platform Engineering creates self-service internal platforms that abstract infrastructure. See benefits, differences from DevOps and how to adopt it.
Read moreAbout the author



