Padrão Factory
Parte da seção Programação Orientada a Objetos do Journey de C# da Coddy — lição 53 de 70.
O padrão Factory é um padrão de criação que delega a criação de objetos para um método ou classe separada. Em vez de usar new diretamente no seu código, você solicita que uma factory crie objetos para você. Isso centraliza a lógica de criação e torna seu código mais flexível.
Considere um cenário onde você precisa criar diferentes tipos de documentos. Sem uma factory, seu código se torna fortemente acoplado a classes específicas:
// Sem Factory - lógica de criação dispersa
IDocument doc;
if (type == "pdf")
doc = new PdfDocument();
else if (type == "word")
doc = new WordDocument();Uma fábrica encapsula essa tomada de decisão em um só lugar:
public interface IDocument
{
void Open();
}
public class PdfDocument : IDocument
{
public void Open() => Console.WriteLine("Opening PDF");
}
public class WordDocument : IDocument
{
public void Open() => Console.WriteLine("Opening Word");
}
public class DocumentFactory
{
public IDocument Create(string type)
{
return type switch
{
"pdf" => new PdfDocument(),
"word" => new WordDocument(),
_ => throw new ArgumentException("Unknown type")
};
}
}Agora, o código cliente simplesmente solicita o que precisa sem conhecer as classes concretas:
var factory = new DocumentFactory();
IDocument doc = factory.Create("pdf");
doc.Open(); // Abrindo PDFO padrão Factory brilha quando você precisa adicionar novos tipos mais tarde. Adicionar um SpreadsheetDocument requer mudanças apenas na factory, não em todos os lugares onde os documentos são criados. Esta separação torna sua base de código mais fácil de manter e testar.
Desafio
FácilVamos construir um sistema de notificação usando o padrão Factory. Em vez de criar diferentes tipos de notificação diretamente em todo o seu código, você centralizará a lógica de criação em uma classe factory que decide qual notificação criar com base em um simples identificador de string.
Você organizará seu código em três arquivos:
Notification.cs: Defina uma interfaceINotificationno namespaceNotificationscom um único métodoSend(string message)que retorna uma string. Em seguida, crie três classes que implementam esta interface:EmailNotification- retorna"Email: {message}"SmsNotification- retorna"SMS: {message}"PushNotification- retorna"Push: {message}"
NotificationFactory.cs: Crie uma classeNotificationFactoryno mesmo namespace com um métodoCreate(string type)que retorna aINotificationapropriada com base na string de tipo:"email"retorna umaEmailNotification"sms"retorna umaSmsNotification"push"retorna umaPushNotification
EmailNotificationcomo padrão.Program.cs: Reúna tudo criando uma instância da factory e usando-a para criar notificações com base na entrada. A factory lida com toda a tomada de decisão sobre qual classe concreta instanciar.
Você receberá duas entradas:
- O tipo de notificação (ex:
sms) - A mensagem a ser enviada (ex:
Your order has shipped)
Use sua factory para criar o tipo de notificação apropriado, chame seu método Send com a mensagem e imprima o resultado.
Por exemplo, se as entradas forem push e Meeting in 5 minutes, a saída deve ser:
Push: Meeting in 5 minutesObserve como seu código principal nunca usa new EmailNotification() ou similar - ele simplesmente pede à factory o que precisa. Se você adicionar posteriormente uma SlackNotification, precisará apenas atualizar a factory, não todos os lugares que criam notificações!
Folha de consulta
O padrão Factory é um padrão de criação que delega a criação de objetos para um método ou classe separada, centralizando a lógica de criação e tornando o código mais flexível.
Sem uma factory, a criação de objetos fica espalhada e fortemente acoplada:
// Sem Factory - lógica de criação espalhada
IDocument doc;
if (type == "pdf")
doc = new PdfDocument();
else if (type == "word")
doc = new WordDocument();Com uma factory, a lógica de criação é encapsulada em um só lugar:
public interface IDocument
{
void Open();
}
public class PdfDocument : IDocument
{
public void Open() => Console.WriteLine("Opening PDF");
}
public class WordDocument : IDocument
{
public void Open() => Console.WriteLine("Opening Word");
}
public class DocumentFactory
{
public IDocument Create(string type)
{
return type switch
{
"pdf" => new PdfDocument(),
"word" => new WordDocument(),
_ => throw new ArgumentException("Unknown type")
};
}
}O código do cliente solicita objetos sem conhecer as classes concretas:
var factory = new DocumentFactory();
IDocument doc = factory.Create("pdf");
doc.Open(); // Opening PDFO padrão Factory facilita a adição de novos tipos - as mudanças são isoladas na factory, não espalhadas por toda a base de código.
Experimente você mesmo
using System;
using Notifications;
class Program
{
public static void Main(string[] args)
{
// Ler a entrada
string type = Console.ReadLine();
string message = Console.ReadLine();
// TODO: Criar uma instância de NotificationFactory
// TODO: Usar a fábrica para criar a notificação apropriada
// TODO: Chamar o método Send e imprimir o resultado
}
}
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 ExternosNamespaces e DiretivasIntrodução a Classes e ObjetosA Palavra-chave 'this'Métodos e ParâmetrosCampos vs PropriedadesConstrutoresInicializadores de ObjetosRecapitulação - Calculadora Simples4Herança
Sintaxe Básica de Herança (:)A Palavra-chave 'base'Palavras-chave Virtual e OverrideClasses SeladasA Classe Base 'object'Recapitulação - Hierarquia de Funcionários7Recursos Avançados
Sobrecarga de OperadoresIndexadores (this[])Sobrescrita de ToString()Métodos de ExtensãoRecapitulação - Lista Personalizada10Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoSingleton Thread-SafePadrão FactoryPadrão Observer (Eventos)Padrão Strategy2Propriedades e Membros Estáticos
Propriedades AutoimplementadasPropriedades de Apenas Leitura/EscritaCampos e Métodos EstáticosClasses EstáticasMembros com Corpo de Expressão5Polimorfismo e Interfaces
Polimorfismo: Compilação vs ExecuçãoInterface vs Classe AbstrataMúltiplas InterfacesInterfaces ExplícitasUpcasting e DowncastingRecapitulação - Calculadora de Formas8Conceitos Avançados de POO
Composição sobre HerançaGenerics (Classes e Métodos)Delegates e EventosAtributos e ReflectionIDisposable e a Instrução usingFundamentos de Injeção de Dependência11Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão Composite3Arquitetura de Classes
Dados de Instância vs EstáticosPalavras-chave 'readonly' e 'const'Campos de SuporteRecapitulação - Gerenciador de Conta Bancária6Encapsulamento
Modificadores de AcessoPropriedades para EncapsulamentoImplementação de Ocultação de DadosPadrões de ImutabilidadeRecapitulação - Registros de Estudantes9Argumentos Variáveis
A Palavra-chave 'params'Parâmetros OpcionaisArgumentos NomeadosSobrecarga de Métodos