Padrões de Projeto Java Comuns

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();
    }
}

Tags: java Singleton Pattern Observer Pattern Decorator Pattern Adapter Pattern

Publicado em 6-1 11:32 por Thomas