Factory Method

Introdução aos Padrões de Criação: Construindo Labirintos

public interface ElementoDeLabirinto {
    public void entra();
}
class Sala implements ElementoDeLabirinto {
    private ElementoDeLabirinto[] vizinhos =
            new ElementoDeLabirinto[4];
    private int númeroDaSala;

    public Sala(int númeroDaSala) {
        ...
    }
    public void entra() {
        ...
    }
    public ElementoDeLabirinto getVizinho(int direção) {
        ...
    }
    public void setVizinho(int direção,
                           ElementoDeLabirinto vizinho) {
        ...
    }
}

class Parede implements ElementoDeLabirinto {
    public Parede() {
        ...
    }
    public void entra() {
        ...
    }
}

class Porta implements ElementoDeLabirinto {
    private Sala sala1, sala2;
    private boolean estáAberta;

    public Porta(ElementoDeLabirinto sala1,
                 ElementoDeLabirinto sala2) {
        ...
    }
    public void entra() {
        ...
    }
    public Sala salaDoOutroLado(Sala sala) {
        ...
    }
}
class Labirinto {
    private Vector salas = new Vector();

    public Labirinto() {
        ...
    }
    public void adicionaSala(Sala sala) {
        ...
    }
    public sala getSala(int númeroDaSala) {
        ...
    }
}
class Jogo {
    ...
    public Labirinto criaLabirinto() {
        Labirinto umLabirinto = new Labirinto();
        Sala sala1 = new Sala(1);
        Sala sala2 = new Sala(2);
        Porta aporta = new Porta(sala1,sala2);

        umLabirinto.adicionaSala(sala1);
        umLabirinto.adicionaSala(sala2);

        sala1.setVizinho(norte, new Parede());
        sala1.setVizinho(leste, aporta);
        sala1.setVizinho(sul, new Parede());
        sala1.setVizinho(oeste, new Parede());

        sala2.setVizinho(norte, new Parede());
        sala2.setVizinho(leste, new Parede());
        sala2.setVizinho(sul, new Parede());
        sala2.setVizinho(oeste, aporta);

        return umLabirinto;
    }
    ...
}

factory2.gif (4787 bytes)

O padrão Factory Method

Objetivo

Também conhecido como

Resumo

Quando usar o padrão Factory Method?

Estrutura genérica

Participantes

Colaborações

Consequências do uso do padrão Factory Method

Considerações de implementação

Exemplo de código: criação de labirintos

class Jogo {
    // Factory Methods com default
    public Labirinto criaLabirinto() {
        return new Labirinto();
    }
    public Sala criaSala(int númeroDaSala) {
        return new Sala(númeroDaSala);
    }
    public Parede criaParede() {
        return new Parede();
    }
    public Porta criaPorta(Sala sala1, Sala sala2) {
        return new Porta(sala1, sala2);
    }

    // Observe que essa função não tem new:
    // ela usa Factory Methods
    // Esta é a *única* diferença com relação
    // à versão original
    // Observe como o método só trata da estrutura do labirinto
    // e não do tipo de elemento que o compõe
    public Labirinto criaLabirinto() {
        Labirinto umLabirinto = criaLabirinto();
        Sala sala1 = criaSala(1);
        Sala sala2 = criaSala(2);
        Porta aPorta = criaPorta(sala1, sala2);

        umLabirinto.adicionaSala(sala1);
        umLabirinto.adicionaSala(sala2);

        sala1.setVizinho(norte, criaParede());
        sala1.setVizinho(leste, aporta);
        sala1.setVizinho(sul, criaParede());
        sala1.setVizinho(oeste, criaParede());

        sala2.setVizinho(norte, criaParede());
        sala2.setVizinho(leste, criaParede());
        sala2.setVizinho(sul, criaParede());
        sala2.setVizinho(oeste, aporta);

        return umLabirinto;
    }
}
// um novo CriadorConcreto
class JogoPerigoso extends Jogo {
    public Parede criaParede() {
        return new ParedeDestrutível();
    }
    public Sala criaSala(int númeroDaSala) {
        return new SalaComBomba(númeroDaSala);
    }
}

// um novo CriadorConcreto
class JogoEncantado extends Jogo {
    public sala criaSala(int númeroDaSala) {
        return new salaEncantada(númeroDaSala, jogaEncantamento());
    }
    public Porta criaPorta(Sala sala1, Sala sala2) {
        return new portaPrecisandoDeEncantamento(sala1, sala2);
    }
    protected Encantamento jogaEncantamento() {
        ...
    }
}

factory3.gif (5223 bytes)

Discussão geral de padrões de criação

Pergunta final para discussão

pat-3 programa anterior próxima