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)); // trueNeste 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.
Desafio
FácilVamos 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 classeNotificationque serve como base para todos os tipos de notificação. Sua classe deve ter:- Um campo
String message - Um construtor nomeado privado
Notification._internalque inicializa a mensagem - Um construtor factory
Notification(String type, String message)que retorna diferentes subtipos de notificação com base no parâmetrotype:- Se o tipo for
'email', retorne umaEmailNotification - Se o tipo for
'sms', retorne umaSMSNotification - Caso contrário, retorne uma
PushNotification
- Se o tipo for
- Um método
send()que imprimeSending: [message]
- Um campo
No mesmo arquivo, crie três subclasses que estendem Notification:
EmailNotification: Sobrescrevasend()para imprimirEmail: [message]SMSNotification: Sobrescrevasend()para imprimirSMS: [message]PushNotification: Sobrescrevasend()para imprimirPush: [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'
send()em cada notificação na ordem listada acima.- Uma notificação de e-mail com a mensagem
Saída esperada:
Email: Welcome!
SMS: Your code is 1234
Push: New update availableFolha 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)); // trueRetornando 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
}
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
1Fundamentos de POO
Arquivos ExternosBibliotecas e ImportaçõesIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosVariáveis de InstânciaFundamentos de ConstrutoresRecapitulação - Calculadora Simples4Null Safety
Introdução ao Null SafetyNullable vs Non-NullableOs Operadores ? e !Palavra-chave Late e Null SafetyOperadores Null-AwareNull Safety em ClassesRecapitulação - Sistema de Perfil de Usuário7Classes Abstratas e Interfaces
Classes AbstratasMétodos AbstratosInterfaces em DartInterfaces ImplícitasImplementando vs EstendendoMúltiplas InterfacesRecapitulação - Calculadora de Formas10Coleções e Generics
Visão Geral de List, Set e MapColeções Type-SafeClasses GenéricasMétodos GenéricosRestrições de GenericsIterable e IteratorRecapitulação - Armazenamento Genérico13Conceitos Avançados de POO
Composição vs HerançaMétodos de ExtensãoClasses ChamáveisClasses Seladas (Dart 3)Records (Dart 3)Patterns & Matching (3.0)Enums com Métodos16Projeto: Gerenciamento de Biblioteca
Visão Geral do ProjetoClasses Livro e Usuário2Construtores em Dart
Construtor PadrãoConstrutores NomeadosListas de InicializaçãoConstrutores ConstantesConstrutores FactoryConstrutores de RedirecionamentoRecapitulação - Shape Builder5Encapsulamento
Membros Públicos vs PrivadosA Convenção do Prefixo _Privacidade em Nível de BibliotecaAprofundamento em Getters & SettersOcultação de InformaçãoRecapitulação - Registros de Estudantes8Mixins
Introdução aos MixinsCriando MixinsUsando Múltiplos MixinsPalavra-chave on em MixinsMixin vs HerançaMixin vs InterfaceRecapitulação - Sistema Animal11Métodos Especiais
Sobrescrita de toString()Sobrescrita de hashCode & ==Interface ComparableMétodo call()Sobrescrita de noSuchMethodRecapitulação - Coleção Personalizada14Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão ObserverPadrão Strategy3Propriedades de Classe
Membros de Instância vs EstáticosCampos Final & ConstVariáveis LateMétodos e Campos EstáticosGetters e SettersRecapitulação - Gerenciador de Conta Bancária6Herança
Herança BásicaA Palavra-chave superSobrescrita de MétodoA Anotação @overrideA Palavra-chave final para ClassesConstrutores e HerançaRecapitulação - Hierarquia de Funcionários9Polimorfismo
Fundamentos do PolimorfismoPolimorfismo via InterfacesVerificação de Tipos em Tempo de ExecuçãoOs Operadores is & asPalavra-chave CovariantRecapitulação - Processador de Pagamentos12POO Assíncrona
Futures e async/awaitFundamentos de StreamsStream ControllersConstrutores AssíncronosAsync em Métodos de ClasseRecapitulação - Data Fetcher15Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Repository