Guia Pratico de Design Patterns para Desenvolvimento Moderno - GoF ate 2025

Intermediario | 2025.12.02

Design Patterns sao um catalogo de solucoes reutilizaveis para problemas de design de software. Passados 30 anos desde o livro do GoF (Gang of Four) de 1994, embora a essencia dos padroes permaneca a mesma, suas formas de aplicacao evoluiram significativamente. Neste artigo, explicamos como aplicar padroes de forma pratica em ambientes de desenvolvimento modernos.

Classificacao dos Design Patterns

flowchart TB
    subgraph DP["Design Patterns"]
        subgraph Creational["Padroes Criacionais"]
            C1["Singleton"]
            C2["Factory Method"]
            C3["Abstract Factory"]
            C4["Builder"]
            C5["Prototype"]
        end

        subgraph Structural["Padroes Estruturais"]
            S1["Adapter"]
            S2["Bridge"]
            S3["Composite"]
            S4["Decorator"]
            S5["Facade"]
            S6["Flyweight"]
            S7["Proxy"]
        end

        subgraph Behavioral["Padroes Comportamentais"]
            B1["Strategy"]
            B2["Observer"]
            B3["Command"]
            B4["State"]
            B5["Template Method"]
            B6["Iterator"]
            B7["Mediator"]
            B8["Memento"]
            B9["Visitor"]
            B10["Chain of Resp."]
        end
    end

Padroes Criacionais

Padrao Factory Method

Delega a criacao de objetos para subclasses, separando a logica de criacao.

// Implementacao de Factory Method em TypeScript moderno

// Interface do produto
interface Notification {
  send(message: string): Promise<void>;
}

// Produtos concretos
class EmailNotification implements Notification {
  constructor(private email: string) {}

  async send(message: string): Promise<void> {
    console.log(`Email to ${this.email}: ${message}`);
    // Logica real de envio de email
  }
}

class SlackNotification implements Notification {
  constructor(private webhookUrl: string) {}

  async send(message: string): Promise<void> {
    console.log(`Slack webhook: ${message}`);
    // Chamada da API do Slack
  }
}

class SMSNotification implements Notification {
  constructor(private phoneNumber: string) {}

  async send(message: string): Promise<void> {
    console.log(`SMS to ${this.phoneNumber}: ${message}`);
    // Chamada da API de envio de SMS
  }
}

// Factory (baseada em funcao - abordagem moderna)
type NotificationType = 'email' | 'slack' | 'sms';

interface NotificationConfig {
  type: NotificationType;
  email?: string;
  webhookUrl?: string;
  phoneNumber?: string;
}

function createNotification(config: NotificationConfig): Notification {
  switch (config.type) {
    case 'email':
      if (!config.email) throw new Error('Email required');
      return new EmailNotification(config.email);
    case 'slack':
      if (!config.webhookUrl) throw new Error('Webhook URL required');
      return new SlackNotification(config.webhookUrl);
    case 'sms':
      if (!config.phoneNumber) throw new Error('Phone number required');
      return new SMSNotification(config.phoneNumber);
    default:
      throw new Error(`Unknown notification type: ${config.type}`);
  }
}

// Exemplo de uso
const notification = createNotification({
  type: 'email',
  email: 'user@example.com'
});
await notification.send('Hello!');

Padrao Builder

Constroi objetos complexos de forma gradual.

// Padrao Builder - Implementacao com Fluent API

interface HttpRequestConfig {
  method: 'GET' | 'POST' | 'PUT' | 'DELETE';
  url: string;
  headers: Record<string, string>;
  body?: unknown;
  timeout: number;
  retries: number;
}

class HttpRequestBuilder {
  private config: Partial<HttpRequestConfig> = {
    method: 'GET',
    headers: {},
    timeout: 30000,
    retries: 0,
  };

  url(url: string): this {
    this.config.url = url;
    return this;
  }

  method(method: HttpRequestConfig['method']): this {
    this.config.method = method;
    return this;
  }

  header(key: string, value: string): this {
    this.config.headers = {
      ...this.config.headers,
      [key]: value,
    };
    return this;
  }

  authorization(token: string): this {
    return this.header('Authorization', `Bearer ${token}`);
  }

  contentType(type: string): this {
    return this.header('Content-Type', type);
  }

  json(data: unknown): this {
    this.config.body = data;
    return this.contentType('application/json');
  }

  timeout(ms: number): this {
    this.config.timeout = ms;
    return this;
  }

  retries(count: number): this {
    this.config.retries = count;
    return this;
  }

  build(): HttpRequestConfig {
    if (!this.config.url) {
      throw new Error('URL is required');
    }
    return this.config as HttpRequestConfig;
  }

  // Metodo conveniente - execucao direta
  async execute<T>(): Promise<T> {
    const config = this.build();
    // Logica real de execucao do fetch
    const response = await fetch(config.url, {
      method: config.method,
      headers: config.headers,
      body: config.body ? JSON.stringify(config.body) : undefined,
    });
    return response.json();
  }
}

// Exemplo de uso
const response = await new HttpRequestBuilder()
  .url('https://api.example.com/users')
  .method('POST')
  .authorization('my-token')
  .json({ name: 'John', email: 'john@example.com' })
  .timeout(5000)
  .retries(3)
  .execute<{ id: string }>();

Padrao Singleton (Alternativas Modernas)

Evite o Singleton tradicional e aproveite containers de DI ou escopo de modulo.

// Nao recomendado: Singleton tradicional (evitar)
class LegacySingleton {
  private static instance: LegacySingleton;

  private constructor() {}

  static getInstance(): LegacySingleton {
    if (!LegacySingleton.instance) {
      LegacySingleton.instance = new LegacySingleton();
    }
    return LegacySingleton.instance;
  }
}

// Recomendado: Singleton no escopo do modulo
// database.ts
class DatabaseConnection {
  constructor(private connectionString: string) {}

  async query<T>(sql: string): Promise<T[]> {
    // Execucao da query
    return [];
  }
}

// Exportar no nivel do modulo
export const db = new DatabaseConnection(process.env.DATABASE_URL!);

// Recomendado: Usar container de DI
// container.ts
import { Container } from 'inversify';

const container = new Container();
container.bind<DatabaseConnection>('Database')
  .to(DatabaseConnection)
  .inSingletonScope();

export { container };

Padroes Estruturais

Padrao Adapter

Faz a ponte entre interfaces incompativeis.

// Adaptar API legada para nova interface

// Sistema legado existente
interface LegacyPaymentSystem {
  processPayment(
    amount: number,
    cardNumber: string,
    expiry: string,
    cvv: string
  ): boolean;
}

class LegacyStripePayment implements LegacyPaymentSystem {
  processPayment(
    amount: number,
    cardNumber: string,
    expiry: string,
    cvv: string
  ): boolean {
    console.log('Processing via legacy Stripe...');
    return true;
  }
}

// Nova interface
interface PaymentGateway {
  charge(payment: PaymentDetails): Promise<PaymentResult>;
}

interface PaymentDetails {
  amount: number;
  currency: string;
  card: {
    number: string;
    expiryMonth: number;
    expiryYear: number;
    cvc: string;
  };
}

interface PaymentResult {
  success: boolean;
  transactionId: string;
  error?: string;
}

// Adapter
class LegacyPaymentAdapter implements PaymentGateway {
  constructor(private legacySystem: LegacyPaymentSystem) {}

  async charge(payment: PaymentDetails): Promise<PaymentResult> {
    const expiry = `${payment.card.expiryMonth}/${payment.card.expiryYear}`;

    const success = this.legacySystem.processPayment(
      payment.amount,
      payment.card.number,
      expiry,
      payment.card.cvc
    );

    return {
      success,
      transactionId: success ? crypto.randomUUID() : '',
      error: success ? undefined : 'Payment failed',
    };
  }
}

// Exemplo de uso
const legacyStripe = new LegacyStripePayment();
const paymentGateway: PaymentGateway = new LegacyPaymentAdapter(legacyStripe);

const result = await paymentGateway.charge({
  amount: 1000,
  currency: 'BRL',
  card: {
    number: '4242424242424242',
    expiryMonth: 12,
    expiryYear: 2025,
    cvc: '123',
  },
});

Padrao Decorator

Adiciona funcionalidades dinamicamente a objetos existentes.

// Implementacao usando Decorators do TypeScript

// Decorator de metodo - saida de log
function Log(
  target: object,
  propertyKey: string,
  descriptor: PropertyDescriptor
): PropertyDescriptor {
  const originalMethod = descriptor.value;

  descriptor.value = async function (...args: unknown[]) {
    console.log(`[${propertyKey}] Called with:`, args);
    const start = performance.now();

    try {
      const result = await originalMethod.apply(this, args);
      const duration = performance.now() - start;
      console.log(`[${propertyKey}] Returned:`, result, `(${duration}ms)`);
      return result;
    } catch (error) {
      console.error(`[${propertyKey}] Error:`, error);
      throw error;
    }
  };

  return descriptor;
}

// Decorator de cache
function Cache(ttlMs: number = 60000) {
  const cache = new Map<string, { value: unknown; expiry: number }>();

  return function (
    target: object,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ): PropertyDescriptor {
    const originalMethod = descriptor.value;

    descriptor.value = async function (...args: unknown[]) {
      const key = JSON.stringify(args);
      const cached = cache.get(key);

      if (cached && cached.expiry > Date.now()) {
        console.log(`[Cache Hit] ${propertyKey}`);
        return cached.value;
      }

      const result = await originalMethod.apply(this, args);
      cache.set(key, { value: result, expiry: Date.now() + ttlMs });
      return result;
    };

    return descriptor;
  };
}

// Decorator de retry
function Retry(maxAttempts: number = 3, delayMs: number = 1000) {
  return function (
    target: object,
    propertyKey: string,
    descriptor: PropertyDescriptor
  ): PropertyDescriptor {
    const originalMethod = descriptor.value;

    descriptor.value = async function (...args: unknown[]) {
      let lastError: Error;

      for (let attempt = 1; attempt <= maxAttempts; attempt++) {
        try {
          return await originalMethod.apply(this, args);
        } catch (error) {
          lastError = error as Error;
          console.warn(`[Retry] Attempt ${attempt}/${maxAttempts} failed`);

          if (attempt < maxAttempts) {
            await new Promise(resolve => setTimeout(resolve, delayMs));
          }
        }
      }

      throw lastError!;
    };

    return descriptor;
  };
}

// Aplicacao dos decorators
class UserService {
  @Log
  @Cache(30000)  // Cache de 30 segundos
  @Retry(3, 1000)
  async getUser(id: string): Promise<User> {
    const response = await fetch(`/api/users/${id}`);
    return response.json();
  }
}

Padrao Proxy

Controla o acesso a objetos.

// Implementacao usando ES6 Proxy

interface User {
  id: string;
  name: string;
  email: string;
  role: 'admin' | 'user';
}

// Proxy de validacao
function createValidatedUser(user: User): User {
  return new Proxy(user, {
    set(target, property, value) {
      if (property === 'email') {
        if (typeof value !== 'string' || !value.includes('@')) {
          throw new Error('Invalid email format');
        }
      }

      if (property === 'role') {
        if (!['admin', 'user'].includes(value)) {
          throw new Error('Invalid role');
        }
      }

      return Reflect.set(target, property, value);
    },
  });
}

// Proxy de lazy loading
function createLazyLoader<T extends object>(
  loader: () => Promise<T>
): T {
  let instance: T | null = null;
  let loading: Promise<T> | null = null;

  return new Proxy({} as T, {
    get(target, property) {
      if (!instance) {
        if (!loading) {
          loading = loader().then(loaded => {
            instance = loaded;
            return loaded;
          });
        }
        // Escolha retornar promise ou bloquear
        return loading.then(inst => (inst as any)[property]);
      }
      return (instance as any)[property];
    },
  });
}

// Proxy de controle de acesso
function createSecureObject<T extends object>(
  obj: T,
  currentUser: User
): T {
  return new Proxy(obj, {
    get(target, property) {
      const value = Reflect.get(target, property);

      // Propriedades restritas a administradores
      const adminOnlyProps = ['password', 'secretKey', 'apiToken'];
      if (adminOnlyProps.includes(String(property))) {
        if (currentUser.role !== 'admin') {
          throw new Error('Access denied: Admin only');
        }
      }

      return value;
    },

    set(target, property, value) {
      if (currentUser.role !== 'admin') {
        throw new Error('Access denied: Read only');
      }
      return Reflect.set(target, property, value);
    },
  });
}

Padroes Comportamentais

Padrao Strategy

Encapsula algoritmos e os torna intercambiaveis.

// Strategy de calculo de precos

interface PricingStrategy {
  calculatePrice(basePrice: number, quantity: number): number;
  getName(): string;
}

class RegularPricing implements PricingStrategy {
  calculatePrice(basePrice: number, quantity: number): number {
    return basePrice * quantity;
  }
  getName(): string {
    return 'Regular';
  }
}

class BulkPricing implements PricingStrategy {
  constructor(private discountThreshold: number, private discountRate: number) {}

  calculatePrice(basePrice: number, quantity: number): number {
    if (quantity >= this.discountThreshold) {
      return basePrice * quantity * (1 - this.discountRate);
    }
    return basePrice * quantity;
  }

  getName(): string {
    return `Bulk (${this.discountRate * 100}% off for ${this.discountThreshold}+)`;
  }
}

class SubscriberPricing implements PricingStrategy {
  constructor(private memberDiscountRate: number) {}

  calculatePrice(basePrice: number, quantity: number): number {
    return basePrice * quantity * (1 - this.memberDiscountRate);
  }

  getName(): string {
    return `Subscriber (${this.memberDiscountRate * 100}% off)`;
  }
}

class SeasonalPricing implements PricingStrategy {
  constructor(
    private seasonalMultiplier: number,
    private seasonName: string
  ) {}

  calculatePrice(basePrice: number, quantity: number): number {
    return basePrice * quantity * this.seasonalMultiplier;
  }

  getName(): string {
    return `Seasonal - ${this.seasonName}`;
  }
}

// Contexto
class ShoppingCart {
  private items: Array<{ name: string; price: number; quantity: number }> = [];
  private pricingStrategy: PricingStrategy = new RegularPricing();

  addItem(name: string, price: number, quantity: number): void {
    this.items.push({ name, price, quantity });
  }

  setPricingStrategy(strategy: PricingStrategy): void {
    this.pricingStrategy = strategy;
  }

  calculateTotal(): number {
    return this.items.reduce((total, item) => {
      return total + this.pricingStrategy.calculatePrice(item.price, item.quantity);
    }, 0);
  }

  getReceipt(): string {
    const lines = this.items.map(item => {
      const subtotal = this.pricingStrategy.calculatePrice(item.price, item.quantity);
      return `${item.name} x${item.quantity}: R$${subtotal}`;
    });

    return [
      `Pricing: ${this.pricingStrategy.getName()}`,
      '---',
      ...lines,
      '---',
      `Total: R$${this.calculateTotal()}`,
    ].join('\n');
  }
}

// Exemplo de uso
const cart = new ShoppingCart();
cart.addItem('Widget', 1000, 5);
cart.addItem('Gadget', 2000, 3);

console.log(cart.getReceipt());
// Pricing: Regular
// Total: R$11000

cart.setPricingStrategy(new BulkPricing(3, 0.15));
console.log(cart.getReceipt());
// Pricing: Bulk (15% off for 3+)
// Total: R$9350

Padrao Observer

Define uma dependencia um-para-muitos entre objetos.

// Implementacao de Observer type-safe em TypeScript

type EventMap = {
  userCreated: { id: string; email: string };
  userUpdated: { id: string; changes: Partial<User> };
  userDeleted: { id: string };
  orderPlaced: { orderId: string; userId: string; total: number };
};

type EventKey = keyof EventMap;
type EventHandler<K extends EventKey> = (event: EventMap[K]) => void | Promise<void>;

class TypedEventEmitter {
  private handlers = new Map<EventKey, Set<EventHandler<any>>>();

  on<K extends EventKey>(event: K, handler: EventHandler<K>): () => void {
    if (!this.handlers.has(event)) {
      this.handlers.set(event, new Set());
    }
    this.handlers.get(event)!.add(handler);

    // Retorna funcao de cancelamento de inscricao
    return () => this.off(event, handler);
  }

  off<K extends EventKey>(event: K, handler: EventHandler<K>): void {
    this.handlers.get(event)?.delete(handler);
  }

  async emit<K extends EventKey>(event: K, data: EventMap[K]): Promise<void> {
    const eventHandlers = this.handlers.get(event);
    if (!eventHandlers) return;

    const promises = Array.from(eventHandlers).map(handler =>
      Promise.resolve(handler(data))
    );

    await Promise.all(promises);
  }

  once<K extends EventKey>(event: K, handler: EventHandler<K>): () => void {
    const wrappedHandler: EventHandler<K> = async (data) => {
      this.off(event, wrappedHandler);
      await handler(data);
    };
    return this.on(event, wrappedHandler);
  }
}

// Exemplo de uso
const eventBus = new TypedEventEmitter();

// Servico de envio de email
eventBus.on('userCreated', async ({ email }) => {
  console.log(`Sending welcome email to ${email}`);
});

// Servico de analytics
eventBus.on('userCreated', ({ id }) => {
  console.log(`Tracking user creation: ${id}`);
});

// Processamento de pedido
eventBus.on('orderPlaced', async ({ orderId, userId, total }) => {
  console.log(`Processing order ${orderId} for user ${userId}: R$${total}`);
});

// Disparo de evento
await eventBus.emit('userCreated', {
  id: 'user-123',
  email: 'user@example.com',
});

Padrao Command

Encapsula operacoes como objetos.

// Implementacao de Command com funcionalidade Undo/Redo

interface Command {
  execute(): Promise<void>;
  undo(): Promise<void>;
  getDescription(): string;
}

// Exemplo de comandos de editor de texto
class TextEditor {
  private content: string = '';

  getContent(): string {
    return this.content;
  }

  setContent(content: string): void {
    this.content = content;
  }

  insertAt(position: number, text: string): void {
    this.content =
      this.content.slice(0, position) + text + this.content.slice(position);
  }

  deleteRange(start: number, end: number): string {
    const deleted = this.content.slice(start, end);
    this.content = this.content.slice(0, start) + this.content.slice(end);
    return deleted;
  }
}

class InsertTextCommand implements Command {
  constructor(
    private editor: TextEditor,
    private position: number,
    private text: string
  ) {}

  async execute(): Promise<void> {
    this.editor.insertAt(this.position, this.text);
  }

  async undo(): Promise<void> {
    this.editor.deleteRange(this.position, this.position + this.text.length);
  }

  getDescription(): string {
    return `Insert "${this.text}" at position ${this.position}`;
  }
}

class DeleteTextCommand implements Command {
  private deletedText: string = '';

  constructor(
    private editor: TextEditor,
    private start: number,
    private end: number
  ) {}

  async execute(): Promise<void> {
    this.deletedText = this.editor.deleteRange(this.start, this.end);
  }

  async undo(): Promise<void> {
    this.editor.insertAt(this.start, this.deletedText);
  }

  getDescription(): string {
    return `Delete from ${this.start} to ${this.end}`;
  }
}

// Command Manager (Invoker)
class CommandManager {
  private history: Command[] = [];
  private redoStack: Command[] = [];

  async execute(command: Command): Promise<void> {
    await command.execute();
    this.history.push(command);
    this.redoStack = [];  // Limpa a pilha de redo ao executar novo comando
  }

  async undo(): Promise<boolean> {
    const command = this.history.pop();
    if (!command) return false;

    await command.undo();
    this.redoStack.push(command);
    return true;
  }

  async redo(): Promise<boolean> {
    const command = this.redoStack.pop();
    if (!command) return false;

    await command.execute();
    this.history.push(command);
    return true;
  }

  getHistory(): string[] {
    return this.history.map(cmd => cmd.getDescription());
  }
}

// Exemplo de uso
const editor = new TextEditor();
const manager = new CommandManager();

await manager.execute(new InsertTextCommand(editor, 0, 'Hello '));
await manager.execute(new InsertTextCommand(editor, 6, 'World!'));
console.log(editor.getContent()); // "Hello World!"

await manager.undo();
console.log(editor.getContent()); // "Hello "

await manager.redo();
console.log(editor.getContent()); // "Hello World!"

Padroes de Arquitetura Modernos

Padrao Repository

Abstrai a logica de acesso a dados.

// Padrao Repository com TypeScript

interface Entity {
  id: string;
}

interface Repository<T extends Entity> {
  findById(id: string): Promise<T | null>;
  findAll(): Promise<T[]>;
  findBy(criteria: Partial<T>): Promise<T[]>;
  save(entity: T): Promise<T>;
  delete(id: string): Promise<boolean>;
}

interface User extends Entity {
  id: string;
  email: string;
  name: string;
  createdAt: Date;
}

// Implementacao em memoria (para testes)
class InMemoryUserRepository implements Repository<User> {
  private users: Map<string, User> = new Map();

  async findById(id: string): Promise<User | null> {
    return this.users.get(id) || null;
  }

  async findAll(): Promise<User[]> {
    return Array.from(this.users.values());
  }

  async findBy(criteria: Partial<User>): Promise<User[]> {
    return Array.from(this.users.values()).filter(user =>
      Object.entries(criteria).every(
        ([key, value]) => user[key as keyof User] === value
      )
    );
  }

  async save(entity: User): Promise<User> {
    this.users.set(entity.id, entity);
    return entity;
  }

  async delete(id: string): Promise<boolean> {
    return this.users.delete(id);
  }
}

// Implementacao com Prisma (para producao)
class PrismaUserRepository implements Repository<User> {
  constructor(private prisma: PrismaClient) {}

  async findById(id: string): Promise<User | null> {
    return this.prisma.user.findUnique({ where: { id } });
  }

  async findAll(): Promise<User[]> {
    return this.prisma.user.findMany();
  }

  async findBy(criteria: Partial<User>): Promise<User[]> {
    return this.prisma.user.findMany({ where: criteria });
  }

  async save(entity: User): Promise<User> {
    return this.prisma.user.upsert({
      where: { id: entity.id },
      update: entity,
      create: entity,
    });
  }

  async delete(id: string): Promise<boolean> {
    try {
      await this.prisma.user.delete({ where: { id } });
      return true;
    } catch {
      return false;
    }
  }
}

Padrao Unit of Work

Rastreia e gerencia alteracoes dentro de uma transacao.

// Implementacao de Unit of Work

interface UnitOfWork {
  begin(): Promise<void>;
  commit(): Promise<void>;
  rollback(): Promise<void>;
  userRepository: Repository<User>;
  orderRepository: Repository<Order>;
}

class PrismaUnitOfWork implements UnitOfWork {
  private transaction: Prisma.TransactionClient | null = null;
  private _userRepository: Repository<User> | null = null;
  private _orderRepository: Repository<Order> | null = null;

  constructor(private prisma: PrismaClient) {}

  async begin(): Promise<void> {
    // Transacao interativa do Prisma
    return new Promise((resolve) => {
      this.prisma.$transaction(async (tx) => {
        this.transaction = tx;
        resolve();
        // A transacao e mantida ate commit/rollback
      });
    });
  }

  get userRepository(): Repository<User> {
    if (!this._userRepository) {
      this._userRepository = new PrismaUserRepository(
        this.transaction || this.prisma
      );
    }
    return this._userRepository;
  }

  get orderRepository(): Repository<Order> {
    if (!this._orderRepository) {
      this._orderRepository = new PrismaOrderRepository(
        this.transaction || this.prisma
      );
    }
    return this._orderRepository;
  }

  async commit(): Promise<void> {
    // Transacao Prisma faz auto-commit
    this.transaction = null;
  }

  async rollback(): Promise<void> {
    throw new Error('Rollback requested');
  }
}

// Exemplo de uso
async function createOrderWithUser(uow: UnitOfWork) {
  await uow.begin();

  try {
    const user = await uow.userRepository.save({
      id: crypto.randomUUID(),
      email: 'new@example.com',
      name: 'New User',
      createdAt: new Date(),
    });

    const order = await uow.orderRepository.save({
      id: crypto.randomUUID(),
      userId: user.id,
      total: 5000,
      status: 'pending',
    });

    await uow.commit();
    return { user, order };
  } catch (error) {
    await uow.rollback();
    throw error;
  }
}

Relacao com Principios SOLID

flowchart LR
    subgraph SOLID["Principios SOLID"]
        S["S - Principio da Responsabilidade Unica (SRP)"]
        O["O - Principio Aberto-Fechado (OCP)"]
        L["L - Principio da Substituicao de Liskov (LSP)"]
        I["I - Principio da Segregacao de Interface (ISP)"]
        D["D - Principio da Inversao de Dependencia (DIP)"]
    end

    subgraph Patterns["Padroes Relacionados"]
        P1["Factory, Strategy, Command"]
        P2["Strategy, Decorator, Template Method"]
        P3["Factory Method, Abstract Factory"]
        P4["Adapter, Facade"]
        P5["Repository, Dependency Injection"]
    end

    S --> P1
    O --> P2
    L --> P3
    I --> P4
    D --> P5

Resumo

Design Patterns sao uma linguagem comum para resolucao de problemas e tambem ajudam no alinhamento de equipes em desenvolvimento colaborativo.

Diretrizes de Selecao

ObjetivoPadrao Recomendado
Flexibilidade na criacao de objetosFactory, Builder
Extensao de codigo existenteDecorator, Adapter
Troca de algoritmosStrategy
Orientacao a eventosObserver
Desfazer operacoesCommand
Abstracao de acesso a dadosRepository

Melhores Praticas em Desenvolvimento Moderno

  1. Evite aplicacao excessiva de padroes - Solucoes simples para problemas simples
  2. Aproveite recursos da linguagem - Sistema de tipos e decorators de TypeScript/Python
  3. Priorize testabilidade - Use DI para permitir injecao de dependencias
  4. Combine com abordagem funcional - Use funcoes para processamento sem estado

Design Patterns sao um meio, nao um fim. E importante entender o problema e selecionar o padrao apropriado.

← Voltar para a lista