seção
Analogia: A Oficina Mecânica
Cada ferramenta resolve um problema recorrente — você não inventa um macaco novo para cada pneu.
Patterns são a caixa de ferramentas do software: Module, Factory, Observer… escolha pela necessidade, não pelo hype.
"Não reinvente a roda. Aprenda a usar as ferramentas certas para cada problema." — adaptado de Christopher Alexander
Design patterns são soluções testadas para problemas recorrentes — não código para copiar, mas plantas que você adapta. A Gang of Four catalogou 23 padrões em 1994; em JavaScript moderno, muitos simplificam ou viram desnecessários.
export function createUser(type, name) { switch (type) { case 'admin': return { name, role: 'admin', permissions: ['read', 'write', 'delete'] }; default: return { name, role: 'viewer', permissions: ['read'] }; }}Neste guia da série 33 Conceitos JS — projeto open source criado por Leonardo Maldonado — você aprende seis padrões úteis no JS: Module, Singleton, Factory, Observer, Proxy e Decorator.
Pré-requisitos: ES Modules, Factories & Classes e Higher-Order Functions.
// metadados do artigo
{
"tag": "advanced topics",
"readTime": "24 min",
"author": "Vanderlei José Alamino",
"source": "33jsconcepts.com",
"series": "33 Conceitos JS",
"part": {
"current": 37,
"total": 38
}
}abrir fonte originalFonte de referência
Conteúdo adaptado a partir do guia original em inglês.
seção
Cada ferramenta resolve um problema recorrente — você não inventa um macaco novo para cada pneu.
Patterns são a caixa de ferramentas do software: Module, Factory, Observer… escolha pela necessidade, não pelo hype.
seção
Soluções típicas catalogadas pela Gang of Four (1994) — 23 padrões em C++/Smalltalk.
| JS moderno | Impacto |
|---|---|
| Funções de 1ª classe | Patterns viram funções simples |
| Closures | Estado privado natural |
| ES Modules | Substitui Module Pattern manual |
| Herança prototipal | Menos hierarquias de classe |
Categorias GoF: Creational (criação), Structural (composição), Behavioral (comunicação) + Module (idioma JS).
seção
Encapsula código com API pública e estado privado.
ES Modules (moderno):
let count = 0;export function increment() { return ++count; }export function getCount() { return count; }IIFE clássico (legado):
const Counter = (function () { let count = 0; return { increment() { return ++count; }, getCount() { return count; }, };})();Projetos novos → ES Modules. Legado → IIFE & Namespaces.
seção
Uma instância global — em JS, módulos ES já são singletons:
export const config = { apiUrl: 'https://api.example.com' };// todo import recebe o mesmo objetoObject.freeze({ apiUrl: '...', debug: false }); // config imutávelProblemas: testes compartilham estado, dependências ocultas, acoplamento.
Quando faz sentido: logger global, config congelada, connection pool — com parcimônia.
seção
Cria objetos sem expor lógica de criação ao caller:
function createUser(type, name) { const base = { name, greet() { return `Hi, I'm ${this.name}`; } }; switch (type) { case 'admin': return { ...base, role: 'admin', permissions: ['read', 'write', 'delete'] }; case 'editor': return { ...base, role: 'editor', permissions: ['read', 'write'] }; default: return { ...base, role: 'viewer', permissions: ['read'] }; }}Use quando: setup complexo, tipos dinâmicos por input, desacoplar criação do uso.
Aprofunde em Factories & Classes.
seção
Publisher notifica subscribers — base de DOM events, React state, EventEmitter, RxJS.
class Observable { constructor() { this.observers = []; } subscribe(fn) { this.observers.push(fn); return () => { this.observers = this.observers.filter(o => o !== fn); }; } notify(data) { this.observers.forEach(fn => fn(data)); }}Três partes: lista de observers, subscribe (com unsubscribe), notify.
FormField observável valida email e conta caracteres no mesmo setValue.
seção
Intercepta operações em objetos — validação, logging, lazy loading:
const userProxy = new Proxy(user, { get(target, prop) { return target[prop]; }, set(target, prop, value) { if (prop === 'age' && value < 0) throw new Error('Age inválida'); target[prop] = value; return true; },});Lazy loading: cria recurso caro só no primeiro acesso via trap get.
Proxy controla acesso; Decorator adiciona comportamento.
seção
Envolve objeto/função para adicionar capacidades sem modificar o original:
const withFlying = (c) => ({ ...c, fly() { return `${c.name} voa!`; } });const duck = withFlying(createCharacter('Duck'));Decorators de função — logging, memoization:
const withMemo = (fn) => { const cache = new Map(); return (...args) => { const key = JSON.stringify(args); if (cache.has(key)) return cache.get(key); const result = fn(...args); cache.set(key, result); return result; };};Relacionado a Currying & Composition e HOFs.
seção
{ name: 'Alice' } simplesMartelo de ouro: usar o pattern que você acabou de aprender em todo lugar.
Pergunte: problema real? solução mais simples? JS já resolve? equipe entende?
seção
| Problema | Pattern | Alternativa JS |
|---|---|---|
| Estado privado + API | Module | ES import/export |
| Uma instância | Singleton | export const x = {} |
| Criação dinâmica | Factory | função retornando objeto |
| Múltiplos listeners | Observer | callback, EventEmitter |
| Validar/acessar | Proxy | getters/setters |
| Comportamento extra | Decorator | HOF, composição |
Regra de ouro: comece simples; introduza pattern quando o problema aparecer.
seção
seção
seção
Você avançou na trilha Advanced Topics — oitavo de nove conceitos avançados.
Conecte patterns com Pure Functions (decorators previsíveis) e Prototypes (herança vs composição).
→ Clean Code — Escrevendo código que humanos entendem — fechamento da trilha Advanced Topics
Fonte de referência: 33jsconcepts.com/concepts/design-patterns ⬀