Menu
Coddy logo textTech

Padrão Factory

Parte da seção Programação Orientada a Objetos do Journey de Dart da Coddy — lição 91 de 110.

O padrão Factory delega a criação de objetos para um método ou classe separada, permitindo que você crie objetos sem especificar sua classe exata. Isso é diferente do construtor factory que você aprendeu anteriormente - o padrão Factory é uma abordagem de design onde a lógica de criação é centralizada e pode retornar tipos diferentes com base na entrada.

Considere um cenário onde você precisa criar diferentes tipos de notificações. Em vez de o cliente decidir qual classe instanciar, uma factory lida com essa decisão:

abstract class Notification {
  void send(String message);
}

class EmailNotification implements Notification {
  @override
  void send(String message) => print('Email: $message');
}

class SMSNotification implements Notification {
  @override
  void send(String message) => print('SMS: $message');
}

class NotificationFactory {
  static Notification create(String type) {
    switch (type) {
      case 'email':
        return EmailNotification();
      case 'sms':
        return SMSNotification();
      default:
        return EmailNotification();
    }
  }
}

void main() {
  var notification = NotificationFactory.create('sms');
  notification.send('Hello!');  // SMS: Hello!
}

O código cliente não precisa saber sobre EmailNotification ou SMSNotification — ele apenas solicita à factory uma notificação de um determinado tipo. Isso torna fácil a adição de novos tipos de notificação: você modifica apenas a factory, não todos os locais que criam notificações.

Use o padrão Factory quando a criação de objetos envolver lógica complexa, quando você desejar ocultar as classes de implementação dos clientes ou quando o tipo exato a ser criado depender de condições de tempo de execução.

challenge icon

Desafio

Fácil

Vamos construir um gerador de documentos usando o padrão Factory! Você criará um sistema que produz diferentes tipos de documentos (relatórios, faturas e cartas) por meio de uma fábrica centralizada, para que o código do cliente não precise conhecer as classes de documentos específicas.

Você organizará seu código em dois arquivos:

  • document_factory.dart: Crie seu sistema de documentos aqui:
    • Uma classe abstrata Document com um método generate(String content) que retorna uma String
    • Três classes concretas que implementam Document:
      • Report - seu método generate retorna === REPORT ===\n[content]\n=============
      • Invoice - seu método generate retorna INVOICE\n--------\n[content]\nTotal Due
      • Letter - seu método generate retorna Dear Reader,\n[content]\nSincerely
    • Uma classe DocumentFactory com um método estático create(String type) que retorna o Document apropriado com base na string de tipo: "report", "invoice", ou "letter". Para qualquer tipo desconhecido, retorne um Letter como padrão
  • main.dart: Importe sua fábrica de documentos e demonstre como a fábrica cria diferentes tipos de documentos sem que o cliente precise conhecer as classes concretas:
    • Use a fábrica para criar um relatório e imprima o resultado de gerá-lo com o conteúdo Sales increased by 25%
    • Imprima uma linha vazia
    • Use a fábrica para criar uma fatura e imprima o resultado de gerá-lo com o conteúdo Widget x3 - $150
    • Imprima uma linha vazia
    • Use a fábrica para criar uma carta e imprima o resultado de gerá-lo com o conteúdo Thank you for your order

Observe como seu arquivo principal interage apenas com a fábrica e o tipo abstrato Document - ele nunca cria diretamente objetos Report, Invoice, ou Letter!

Saída esperada:

=== REPORT ===
Sales increased by 25%
=============

INVOICE
--------
Widget x3 - $150
Total Due

Dear Reader,
Thank you for your order
Sincerely

Folha de consulta

O padrão Factory delega a criação de objetos para um método ou classe separada, permitindo que você crie objetos sem especificar sua classe exata. A lógica de criação é centralizada e pode retornar tipos diferentes com base na entrada.

Estrutura básica do padrão Factory:

abstract class Notification {
  void send(String message);
}

class EmailNotification implements Notification {
  @override
  void send(String message) => print('Email: $message');
}

class SMSNotification implements Notification {
  @override
  void send(String message) => print('SMS: $message');
}

class NotificationFactory {
  static Notification create(String type) {
    switch (type) {
      case 'email':
        return EmailNotification();
      case 'sms':
        return SMSNotification();
      default:
        return EmailNotification();
    }
  }
}

void main() {
  var notification = NotificationFactory.create('sms');
  notification.send('Hello!');  // SMS: Hello!
}

O código do cliente interage apenas com a factory e o tipo abstrato, não com as classes de implementação concreta. Isso torna fácil a adição de novos tipos - você modifica apenas a factory.

Use o padrão Factory quando:

  • A criação de objetos envolve lógica complexa
  • Você deseja ocultar as classes de implementação dos clientes
  • O tipo exato a ser criado depende de condições em tempo de execução

Experimente você mesmo

import 'document_factory.dart';

void main() {
  // TODO: Use DocumentFactory.create() para criar um relatório
  // Em seguida, imprima o resultado de gerá-lo com o conteúdo: "Sales increased by 25%"
  
  // TODO: Imprima uma linha vazia
  
  // TODO: Use DocumentFactory.create() para criar uma fatura
  // Em seguida, imprima o resultado de gerá-lo com o conteúdo: "Widget x3 - \$150"
  
  // TODO: Imprima uma linha vazia
  
  // TODO: Use DocumentFactory.create() para criar uma carta
  // Em seguida, imprima o resultado de gerá-lo com o conteúdo: "Thank you for your order"
}
quiz iconTeste seus conhecimentos

Esta lição inclui um quiz rápido. Comece a lição para respondê-lo e acompanhar seu progresso.

Todas as lições de Programação Orientada a Objetos