Atividade 05: Factory Method
Exercício 1: Aplicações
Seção intitulada “Exercício 1: Aplicações”Para cada cenário abaixo, indique se o padrão Factory Method é apropriado ou não e justifique em 2–3 frases.
- Um serviço de notificações que precisa enviar mensagens por email, SMS e push. O fluxo de envio é sempre o mesmo (montar a mensagem, enviar, registrar log), mas cada canal entrega de um jeito diferente, e novos canais entram frequentemente.
- Uma classe simples
Pontocom apenas dois campos obrigatórios (x,y), utilizada em um sistema de CAD e instanciada dezenas de vezes por segundo através do construtor tradicional. - Um framework de exportação de relatórios (PDF, CSV, Excel). O módulo principal não deve conhecer as classes concretas de exportação, e novas exportações devem entrar apenas com novas subclasses, sem alterar o fluxo de geração.
- Uma aplicação que precisa criar um cliente HTTP diferente conforme o ambiente: uma implementação mock nos testes e uma real (OkHttp) em produção, sem que o restante do código mude.
- Uma classe
Produtocom três campos obrigatórios (nome,preco,quantidadeEstoque), criada em um único ponto do sistema através do construtor tradicional e sem variações.
Para cada item, responda:
- “Faz sentido usar Factory Method” ou “Não faz sentido usar Factory Method”.
- Explique rapidamente o porquê (acoplamento com classes concretas, variação de criação, extensibilidade, overengineering, etc.).
Exercício 2: Analogia
Seção intitulada “Exercício 2: Analogia”Crie uma analogia própria para explicar o padrão Factory Method para alguém que não é da área de TI.
Na aula, usamos uma rede de restaurantes: o processo de atendimento é o mesmo em todas as lojas, mas cada loja (hamburgueria, pizzaria) monta o seu próprio produto, sem que o cliente precise saber como o prato é preparado. Agora crie uma outra analogia.
Descreva uma situação do mundo real em que:
- exista um processo fixo que usa um produto criado “na hora”,
- cada unidade/equipe decida qual produto concreto será criado,
- e o processo principal continue funcionando quando um novo tipo de produto é adicionado.
Exercício 3: Anti-pattern
Seção intitulada “Exercício 3: Anti-pattern”Considere o código Java abaixo, usado para enviar notificações aos usuários de um sistema:
public class NotificadorService {
public void enviar(String canal, String destinatario, String mensagem) { if (canal.equals("email")) { new EmailNotificador().enviar(destinatario, mensagem); } else if (canal.equals("sms")) { new SmsNotificador().enviar(destinatario, mensagem); } else if (canal.equals("push")) { new PushNotificador().enviar(destinatario, mensagem); } }}
public class EmailNotificador { public void enviar(String destinatario, String mensagem) { /* ... */ }}
public class SmsNotificador { public void enviar(String destinatario, String mensagem) { /* ... */ }}
public class PushNotificador { public void enviar(String destinatario, String mensagem) { /* ... */ }}Responda:
- Por que essa forma de escolher o canal com
if/elseé um problema de design? - O que precisa ser alterado para adicionar um novo canal (por exemplo, WhatsApp)? Que riscos essa mudança traz para o código que já foi testado?
- Proponha uma solução usando o padrão Factory Method, explicando em linhas gerais: a interface do produto (
Notificador), o criador abstrato com o método fábrica e os criadores concretos por canal.
Exercício 4: Exemplo real
Seção intitulada “Exercício 4: Exemplo real”Acesse os seguintes arquivos em um projeto open source:
- Projeto:
iluwatar/java-design-patterns(um dos repositórios de padrões de projeto mais populares do GitHub) - Arquivos:
Esse exemplo implementa o Factory Method com ferreiros (blacksmiths): a interface Blacksmith declara o método fábrica manufactureWeapon(...), e cada ferreiro concreto (como o ElfBlacksmith, ou o OrcBlacksmith do mesmo pacote) decide qual arma criar. É a mesma estrutura vista em aula com a Logistica e o método criarTransporte().
Responda:
- Que papel a interface
Blacksmithexerce no padrão? Qual é o método fábrica declarado nela e qual o seu tipo de retorno? - No
ElfBlacksmith, o que o métodomanufactureWeapon(...)retorna? Por que o tipo de retorno é a interfaceWeapone não a classe concreta (ElfWeapon)? - O cliente do exemplo (a classe
Appdo mesmo pacote) trabalha comBlacksmitheWeapon— abstrações — e troca de ferreiro (elfo ou orc). O que seria necessário para adicionar um novo ferreiro (por exemplo, um anão) sem alterar o código que usa as armas? Relacione com o princípio OCP.
Exercício 5: Implementação
Seção intitulada “Exercício 5: Implementação”Imagine que você foi contratado para criar o Sistema de Notificações de um portal acadêmico.
O sistema precisa notificar os alunos por diferentes canais (email, SMS e push) sempre seguindo o mesmo fluxo:
- montar a mensagem,
- escolher o canal,
- enviar,
- registrar no log.
Como o fluxo é sempre o mesmo e só muda qual canal é criado, repetir o envio com new para cada canal deixaria o código acoplado às classes concretas.
Sua missão
Seção intitulada “Sua missão”Implemente, em Java, um sistema que centralize a criação do notificador em um método fábrica, usando o padrão Factory Method.
- Crie a interface
Notificador:- Contrato:
void enviar(String destinatario, String mensagem).
- Contrato:
- Crie pelo menos três produtos concretos:
EmailNotificador,SmsNotificadorePushNotificador, cada um implementandoNotificadore imprimindo (ou registrando) uma mensagem que identifique o canal usado.
- Crie a classe abstrata
NotificacaoService(o Creator):- Um método público
notificar(String destinatario, String mensagem)que representa o fluxo comum (montar mensagem, chamar o método fábrica, enviar, registrar log). - Um método fábrica abstrato
protected abstract Notificador criarNotificador();.
- Um método público
- Crie os criadores concretos:
EmailService,SmsServiceePushService, que estendemNotificacaoServicee sobrescrevemcriarNotificador()devolvendo o notificador correspondente.
- Crie uma classe de teste, por exemplo
Main, que:- Instancie
EmailService,SmsServiceePushService. - Envie a mesma mensagem pelos três canais usando o método
notificar(...). - Mostre que o fluxo é o mesmo e apenas o canal criado muda (ex.: a saída identifica o canal).
- Explique, em um comentário ou README, como adicionar um novo canal (ex.:
WhatsApp) exigiria apenas uma nova subclasse deNotificadore uma nova subclasse deNotificacaoService, sem alterar o fluxo existente.
- Instancie