Padrão Singleton
O padrão Singleton garante que uma classe tenha apenas uma instância e fornece um ponto global de acesso a ela. Normalmente, o construtor é privado e uma instância única é obtida através de um método estático, como obterInstancia().
Exemplo básico (não thread-safe):
public class UnicoPadrao {
private static UnicoPadrao instancia;
private UnicoPadrao() {}
public static UnicoPadrao obterInstancia() {
if (instancia == null) {
instancia = new UnicoPadrao();
}
return instancia;
}
}
Implementação thread-safe (sincronizada):
public class UnicoPadraoSeguro {
private static UnicoPadraoSeguro instancia;
private UnicoPadraoSeguro() {}
public static synchronized UnicoPadraoSeguro obterInstancia() {
if (instancia == null) {
instancia = new UnicoPadraoSeguro();
}
return instancia;
}
}
Implementação eagerly initialized (inicialização antecipada):
public class UnicoPadraoEager {
private static final UnicoPadraoEager INSTANCIA = new UnicoPadraoEager();
private UnicoPadraoEager() {}
public static UnicoPadraoEager obterInstancia() {
return INSTANCIA;
}
}
Usando classe estática interna:
public class UnicoPadraoInterno {
private static class Detentor {
private static final UnicoPadraoInterno INSTANCIA = new UnicoPadraoInterno();
}
private UnicoPadraoInterno() {}
public static UnicoPadraoInterno obterInstancia() {
return Detentor.INSTANCIA;
}
}
Implementação com enumeração:
public enum UnicoPadraoEnum {
INSTANCIA;
public void executarAcao() {}
}
Double-checked locking (verfiicação dupla):
public class UnicoPadraoDuplo {
private volatile static UnicoPadraoDuplo instancia;
private UnicoPadraoDuplo() {}
public static UnicoPadraoDuplo obterInstancia() {
if (instancia == null) {
synchronized (UnicoPadraoDuplo.class) {
if (instancia == null) {
instancia = new UnicoPadraoDuplo();
}
}
}
return instancia;
}
}
Padrão Observer
O padrão Observer define uma dependência um-para-muitos entre objetos. Quando o estado de um objeto muda, todos os seus dependentes são notificados e atualizados automaticamente.
Exemplo: três classes – Notificador (sujeito) e dois observadores ObservadorA e ObservadorB.
public interface Observador {
void receberNotificacao(String mensagem);
}
public class ObservadorA implements Observador {
private String nome = "Observador A";
@Override
public void receberNotificacao(String msg) {
System.out.println(nome + " recebeu: " + msg);
}
}
public class ObservadorB implements Observador {
private String nome = "Observador B";
@Override
public void receberNotificacao(String msg) {
System.out.println(nome + " recebeu: ->" + msg);
}
}
import java.util.ArrayList;
import java.util.List;
public class Notificador {
private List<Observador> observadores = new ArrayList<>();
public void adicionarObservador(Observador obs) {
observadores.add(obs);
}
public void notificarTodos() {
for (Observador obs : observadores) {
obs.receberNotificacao("Evento ocorrido!");
}
}
}
public class TesteObserver {
public static void main(String[] args) {
Notificador notificador = new Notificador();
ObservadorA obsA = new ObservadorA();
ObservadorB obsB = new ObservadorB();
notificador.adicionarObservador(obsA);
notificador.adicionarObservador(obsB);
notificador.notificarTodos();
}
}
Padrão Decorator
O padrão Decorator permite adicionar responsabilidades a objetos dinamicamente, envolvendo-os em camadas. Por exemplo, streams de I/O em Java usam este padrão.
Exemplo: construir um item composto como um sanduíche.
public class Item {
private String descricao;
public Item() {}
public Item(String descricao) {
this.descricao = descricao;
}
public String descrever() {
return descricao;
}
}
public class Pao extends Item {
private Item itemBase;
public Pao(Item itemBase) {
this.itemBase = itemBase;
}
public String descrever() {
return itemBase.descrever() + " + pão";
}
}
public class Creme extends Item {
private Item itemBase;
public Creme(Item itemBase) {
this.itemBase = itemBase;
}
public String descrever() {
return itemBase.descrever() + " + creme";
}
}
public class Legume extends Item {
private Item itemBase;
public Legume(Item itemBase) {
this.itemBase = itemBase;
}
public String descrever() {
return itemBase.descrever() + " + legume";
}
}
public class TesteDecorator {
public static void main(String[] args) {
Item sanduiche = new Pao(new Legume(new Creme(new Item("linguiça"))));
System.out.println(sanduiche.descrever());
}
}
Padrão Adapter
O padrão Adapter converte a interface de uma classe em outra interface que o cliente espera. Ele permite classes com interfaces incompatíveis trabalharem juntas.
Exemplo: adaptar uma tensão elétrica.
public class TesteAdapter {
public static void main(String[] args) {
DispositivoEletrico dispositivo = new DispositivoEletrico();
AdaptadorTensao adaptador = new AdaptadorTensao();
dispositivo.conectar(adaptador);
dispositivo.carregar();
}
}
class DispositivoEletrico {
public static final int TENSAO_ORIGINAL = 220;
private AdaptadorTensao adaptador;
public void carregar() {
adaptador.transformarTensao();
}
public void conectar(AdaptadorTensao adaptador) {
this.adaptador = adaptador;
}
}
class AdaptadorTensao {
public void transformarTensao() {
System.out.println("Carregando...");
System.out.println("Tensão original: " + DispositivoEletrico.TENSAO_ORIGINAL + "V");
System.out.println("Tensão adaptada: " + (DispositivoEletrico.TENSAO_ORIGINAL - 200) + "V");
}
}
Padrão Factory
O padrão Factory define uma interface para criar objetos, mas permite que subclasses decidam qual classe instanciar.
Exemplo simples de fábrica:
abstract class Veiculo {
abstract void dirigir();
abstract void parar();
}
class Automovel implements Veiculo {
public void dirigir() {
System.out.println("Automovel iniciando...");
}
public void parar() {
System.out.println("Automovel parando...");
}
}
class Caminhao implements Veiculo {
public void dirigir() {
System.out.println("Caminhao iniciando...");
}
public void parar() {
System.out.println("Caminhao parando...");
}
}
class FabricaVeiculos {
public static Veiculo criarVeiculo(String tipo) {
Veiculo veiculo = null;
if ("automovel".equals(tipo)) {
veiculo = new Automovel();
} else if ("caminhao".equals(tipo)) {
veiculo = new Caminhao();
}
return veiculo;
}
}
public class TesteFactory {
public static void main(String[] args) {
Veiculo v = FabricaVeiculos.criarVeiculo("automovel");
if (v != null) {
v.dirigir();
v.parar();
}
}
}
Padrão Factory Method:
public interface Transporte {
void mover();
}
public class Aviao implements Transporte {
public void mover() {
System.out.println("Aviao voando...");
}
}
public class Carro implements Transporte {
public void mover() {
System.out.println("Carro dirigindo...");
}
}
public abstract class FabricaTransporte {
abstract Transporte criarTransporte();
}
public class FabricaAviao extends FabricaTransporte {
public Transporte criarTransporte() {
return new Aviao();
}
}
public class FabricaCarro extends FabricaTransporte {
public Transporte criarTransporte() {
return new Carro();
}
}
public class TesteFactoryMethod {
public static void main(String[] args) {
FabricaTransporte fabrica = new FabricaCarro();
Transporte t = fabrica.criarTransporte();
t.mover();
}
}
Padrão Abstract Factory:
public interface Veiculo2 {
void operar();
}
public interface Ferramenta {
void usar();
}
public interface Comida {
void consumir();
}
public class Carro2 implements Veiculo2 {
public void operar() {
System.out.println("Carro operando...");
}
}
public class Martelo implements Ferramenta {
public void usar() {
System.out.println("Martelo usado...");
}
}
public class Fruta implements Comida {
public void consumir() {
System.out.println("Fruta consumida...");
}
}
public abstract class FabricaAbstrata {
public abstract Veiculo2 criarVeiculo();
public abstract Ferramenta criarFerramenta();
public abstract Comida criarComida();
}
public class FabricaConcreta extends FabricaAbstrata {
public Veiculo2 criarVeiculo() {
return new Carro2();
}
public Ferramenta criarFerramenta() {
return new Martelo();
}
public Comida criarComida() {
return new Fruta();
}
}
public class TesteAbstractFactory {
public static void main(String[] args) {
FabricaAbstrata fabrica = new FabricaConcreta();
Veiculo2 v = fabrica.criarVeiculo();
Ferramenta f = fabrica.criarFerramenta();
Comida c = fabrica.criarComida();
v.operar();
f.usar();
c.consumir();
}
}
Padrão Proxy
O padrão Proxy fornece um substituto ou marcador de lugar para outro objeto para controlar o acesso a ele. Pode ser estático ou dinâmico.
Exemplo estático: um serviço de planejamento de eventos.
public interface ServicoEvento {
void organizarEvento();
}
public class ClienteReal implements ServicoEvento {
public void organizarEvento() {
System.out.println("Evento organizado pelo cliente.");
}
}
public class EmpresaProxy implements ServicoEvento {
private ServicoEvento servico;
public EmpresaProxy(ServicoEvento servico) {
this.servico = servico;
}
public void organizarEvento() {
System.out.println("Preparando logística...");
System.out.println("Configurando equipamentos...");
servico.organizarEvento();
System.out.println("Limpeza pós-evento realizada.");
}
}
public class TesteProxy {
public static void main(String[] args) {
ServicoEvento cliente = new ClienteReal();
ServicoEvento proxy = new EmpresaProxy(cliente);
proxy.organizarEvento();
}
}