Padrão Factory
Parte da seção Programação Orientada a Objetos do Journey de Java da Coddy — lição 66 de 87.
O Factory Pattern é um padrão de projeto criacional 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 fábrica crie objetos para você. Isso é especialmente útil quando você tem várias classes relacionadas que compartilham uma interface ou pai comum.
Considere um sistema de notificação que pode enviar e-mails, SMS ou notificações push. Sem uma factory, seu código precisaria conhecer cada classe concreta:
// Sem Factory - o cliente deve conhecer todas as classes concretas
Notification notification;
if (type.equals("email")) {
notification = new EmailNotification();
} else if (type.equals("sms")) {
notification = new SMSNotification();
}Com o Factory Pattern, você centraliza esta lógica de criação:
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Email: " + message);
}
}
public class SMSNotification implements Notification {
public void send(String message) {
System.out.println("SMS: " + message);
}
}
public class NotificationFactory {
public static Notification create(String type) {
if (type.equals("email")) {
return new EmailNotification();
} else if (type.equals("sms")) {
return new SMSNotification();
}
return null;
}
}Agora o código do cliente está mais limpo e não depende de classes concretas:
Notification notification = NotificationFactory.create("email");
notification.send("Hello!"); // Saída: Email: Hello!O principal benefício é que a adição de novos tipos de notificação exige apenas a atualização da factory — o código do cliente permanece inalterado. Isso segue o princípio de programar para uma interface, tornando seu sistema mais flexível e fácil de estender.
Desafio
FácilVamos construir um sistema de desenho de formas usando o Factory Pattern! Em vez de criar objetos de forma diretamente em todo o seu código, você centralizará a lógica de criação em uma fábrica que produz diferentes tipos de formas com base em um identificador de string simples.
Você organizará seu código em quatro arquivos:
Shape.java: Defina uma interface chamadaShapeque sirva como o contrato comum para todas as formas. Sua interface deve declarar um único métododraw()que não retorna nada, mas imprime informações sobre a forma que está sendo desenhada.Shapes.java: Crie três classes que implementem sua interfaceShape:Circle- seu métododraw()deve imprimirDrawing a CircleRectangle- seu métododraw()deve imprimirDrawing a RectangleTriangle- seu métododraw()deve imprimirDrawing a TriangleShapeFactory.java: Crie a classe de fábrica que lida com a criação de formas. SuaShapeFactorydeve ter um método estáticocreateShape(String type)que retorna umShape. Com base no parâmetro type:- Se type for igual a
"circle", retorne um novoCircle - Se type for igual a
"rectangle", retorne um novoRectangle - Se type for igual a
"triangle", retorne um novoTriangle - Para qualquer outro valor, retorne
null
- Se type for igual a
Main.java: Reúna seu sistema de fábrica! Você receberá duas entradas: dois tipos de formas (ambas Strings).Para cada entrada, use sua
ShapeFactorypara criar a forma e armazená-la em uma variávelShape. Se a fábrica retornar uma forma válida (não nula), chame seu métododraw(). Se retornar nulo, imprimaUnknown shape: [type]onde [type] é a entrada que foi fornecida.Processe ambas as entradas em ordem, cada uma em sua própria linha de saída.
Você receberá duas entradas em ordem: o primeiro tipo de forma (String) e o segundo tipo de forma (String).
Observe como sua classe Main nunca usa new Circle() ou new Rectangle() diretamente — ela conhece apenas a interface Shape e solicita à fábrica a criação dos objetos. Este é o poder do Factory Pattern: o código do cliente é desacoplado das classes concretas!
Folha de consulta
O Factory Pattern (Padrão de Fábrica) é um padrão de projeto criacional que delega a criação de objetos para um método ou classe separada, centralizando a lógica de criação e desacoplando o código do cliente das implementações concretas.
Em vez de instanciar objetos diretamente com new, você usa um método de fábrica:
// Sem Factory - o cliente depende de classes concretas
Notification notification;
if (type.equals("email")) {
notification = new EmailNotification();
} else if (type.equals("sms")) {
notification = new SMSNotification();
}Com o Factory Pattern, defina uma interface comum e implementações concretas:
public interface Notification {
void send(String message);
}
public class EmailNotification implements Notification {
public void send(String message) {
System.out.println("Email: " + message);
}
}
public class SMSNotification implements Notification {
public void send(String message) {
System.out.println("SMS: " + message);
}
}Crie uma classe de fábrica com um método de criação estático:
public class NotificationFactory {
public static Notification create(String type) {
if (type.equals("email")) {
return new EmailNotification();
} else if (type.equals("sms")) {
return new SMSNotification();
}
return null;
}
}O código do cliente usa a fábrica em vez da instanciação direta:
Notification notification = NotificationFactory.create("email");
notification.send("Hello!"); // Saída: Email: Hello!Benefícios: Adicionar novos tipos requer apenas a atualização da fábrica — o código do cliente permanece inalterado. Isso segue o princípio de programar para uma interface, tornando os sistemas mais flexíveis e fáceis de estender.
Experimente você mesmo
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// Lê dois tipos de formas
String type1 = scanner.nextLine();
String type2 = scanner.nextLine();
// TODO: Use ShapeFactory para criar a primeira forma
// Se a forma não for null, chame draw()
// Se a forma for null, imprima "Unknown shape: [type]"
// TODO: Faça o mesmo para a segunda forma
}
}
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 ExternosIntrodução à POOClasses vs ObjetosA Palavra-chave thisMétodosCampos (Atributos)Método ConstrutorSobrecarga de ConstrutorRecapitulação - Calculadora Simples4Herança
Herança Básica (extends)A Palavra-chave superSobrescrita de Método (@Override)Encadeamento de ConstrutoresA Classe ObjectHerança Simples e MultinívelPor que não há Herança Múltipla de ClassesRecapitulação - Hierarquia de Funcionários7Métodos Especiais e a Classe Object
Método toString()equals() e hashCode()Método clone()compareTo() e ComparableInterface ComparatorRecapitulação - Ordenação Personalizada2Modificadores de Acesso e Encapsulamento
Visão Geral dos Níveis de AcessoMétodos Getter e SetterOcultação de InformaçõesA Palavra-chave finalRecapitulação - Gerenciador de Conta Bancária5Polimorfismo
Fundamentos de Sobrecarga de MétodosSobrescrita de Métodos (Tempo de Execução)Upcasting e DowncastingO Operador instanceofClasses e Métodos AbstratosRecapitulação - Calculadora de Formas8Conceitos Avançados de OOP
Composição vs HerançaAgregação vs ComposiçãoClasses Internas, Aninhadas e AnônimasEnums e Métodos de EnumRecords (Java 16+)Classes Seladas (Java 17+)11Padrões de Projeto Parte 1
Introdução aos Padrões de ProjetoPadrão SingletonPadrão FactoryPadrão BuilderPadrão ObserverPadrão Strategy3Propriedades de Classe e Membros Estáticos
Variáveis de Instância vs EstáticasMétodos EstáticosBlocos EstáticosConstantes (static final)Recapitulação - Contador e Utilitário6Interfaces e Classes Abstratas
Introdução às InterfacesImplementando InterfacesImplementação de Múltiplas InterfacesDefault e Static em InterfacesClasses Abstratas vs InterfacesInterfaces FuncionaisRecapitulação - Sistema de Pagamento9Generics
Introdução a GenericsClasses GenéricasMétodos GenéricosParâmetros de Tipos DelimitadosWildcards (?, extends, super)Recapitulação - Container Genérico12Padrões de Projeto Parte 2
Padrão CommandPadrão AdapterPadrão DecoratorPadrão Template MethodPadrão StatePadrão CompositePadrão Iterator