Menu
Coddy logo textTech

Construtores Factory

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

Um construtor factory é um construtor especial que nem sempre cria uma nova instância. Diferente dos construtores comuns, um construtor factory pode retornar uma instância existente, um subtipo ou até mesmo nulo (se for anulável). Você o declara usando a palavra-chave factory.

class Logger {
  static final Logger _instance = Logger._internal();
  
  // Construtor nomeado privado
  Logger._internal();
  
  // Construtor factory
  factory Logger() {
    return _instance;
  }
}

Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // true

Neste exemplo, o construtor factory sempre retorna a mesma instância. Não importa quantas vezes você chame Logger(), você obtém o objeto idêntico. Este padrão é comumente usado para implementar singletons.

Construtores factory diferem dos construtores regulares de uma maneira fundamental: eles não têm acesso a this porque eles podem não criar uma nova instância de forma alguma. Em vez disso, eles devem retornar explicitamente um objeto:

class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle();
    if (type == 'square') return Square();
    return Rectangle();
  }
}

class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }

Construtores factory são úteis quando você precisa de controle sobre a criação de instâncias, como retornar objetos em cache, implementar pools de objetos ou decidir qual subtipo instanciar com base em parâmetros de entrada.

challenge icon

Desafio

Fácil

Vamos construir um sistema de notificação que usa construtores factory para criar diferentes tipos de notificações com base em uma entrada de string simples.

Você criará dois arquivos para organizar seu código:

  • notification.dart: Defina uma classe Notification que serve como base para todos os tipos de notificação. Sua classe deve ter:
    • Um campo String message
    • Um construtor nomeado privado Notification._internal que inicializa a mensagem
    • Um construtor factory Notification(String type, String message) que retorna diferentes subtipos de notificação com base no parâmetro type:
      • Se o tipo for 'email', retorne uma EmailNotification
      • Se o tipo for 'sms', retorne uma SMSNotification
      • Caso contrário, retorne uma PushNotification
    • Um método send() que imprime Sending: [message]

No mesmo arquivo, crie três subclasses que estendem Notification:

  • EmailNotification: Sobrescreva send() para imprimir Email: [message]
  • SMSNotification: Sobrescreva send() para imprimir SMS: [message]
  • PushNotification: Sobrescreva send() para imprimir Push: [message]

Cada subclasse precisa de um construtor que receba uma message e a passe para o pai usando super._internal(message).

  • main.dart: Importe sua classe de notificação e crie três notificações usando o construtor factory:
    • Uma notificação de e-mail com a mensagem 'Welcome!'
    • Uma notificação de SMS com a mensagem 'Your code is 1234'
    • Uma notificação push com a mensagem 'New update available'
    Chame send() em cada notificação na ordem listada acima.

Saída esperada:

Email: Welcome!
SMS: Your code is 1234
Push: New update available

Folha de consulta

Um construtor factory é um construtor especial declarado com a palavra-chave factory que nem sempre cria uma nova instância. Ao contrário dos construtores comuns, ele pode retornar uma instância existente, um subtipo ou nulo.

Construtores factory não têm acesso a this e devem retornar explicitamente um objeto.

Exemplo de padrão Singleton:

class Logger {
  static final Logger _instance = Logger._internal();
  
  Logger._internal(); // Private named constructor
  
  factory Logger() {
    return _instance; // Always returns same instance
  }
}

Logger log1 = Logger();
Logger log2 = Logger();
print(identical(log1, log2)); // true

Retornando subtipos diferentes:

class Shape {
  factory Shape(String type) {
    if (type == 'circle') return Circle();
    if (type == 'square') return Square();
    return Rectangle();
  }
}

class Circle extends Shape { Circle() : super._(); }
class Square extends Shape { Square() : super._(); }
class Rectangle extends Shape { Rectangle() : super._(); }

Construtores factory são úteis para controlar a criação de instâncias, como retornar objetos em cache, implementar pools de objetos ou decidir qual subtipo instanciar com base em parâmetros de entrada.

Experimente você mesmo

import 'notification.dart';

void main() {
  // TODO: Crie uma notificação por e-mail com a mensagem 'Welcome!'
  
  // TODO: Crie uma notificação por SMS com a mensagem 'Your code is 1234'
  
  // TODO: Crie uma notificação push com a mensagem 'New update available'
  
  // TODO: Chame send() em cada notificação em ordem
}
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