Abstract Factory

Objetivo

Também chamado de

Resumo

Exemplo: look-and-feel de GUIs

abstractfactory1.gif (9797 bytes)

O padrão Abstract Factory

Quando usar o padrão Abstract Factory?

Estrutura genérica

abstractfactory2.gif (9872 bytes)

Participantes

Colaborações entre objetos

Consequências do uso do padrão Abstract Factory

Considerações de implementação

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

public interface FactoryDeLabirintoIF {
  public LabirintoIF criaLabirinto();
  public SalaIF criaSala(int númeroDaSala);
  public ParedeIF criaParede() {
  public PortaIF criaPorta(SalaIF sala1, SalaIF sala2) {
}

public class FactoryDeLabirinto implements FactoryDeLabirintoIF {
  private static FactoryDeLabirintoIF instânciaÚnica = null;

  private FactoryDeLabirinto() {}

  public static FactoryDeLabirintoIF getInstance(String tipo) {
    if(instânciaÚnica == null) {
      if(tipo.equals("perigoso")) {
        instânciaÚnica = new FactoryDeLabirintoPerigoso();
      } else if(tipo.equals("encantado")) {
        instânciaÚnica = new FactoryDeLabirintoEncantado();
      } else {
        instânciaÚnica = new FactoryDeLabirinto();
      }
    }
    return instânciaÚnica;
  }

  // Factory Methods
  // Tem default para as Factory Methods
  public LabirintoIF criaLabirinto() {
    return new Labirinto();
  }

  public SalaIF criaSala(int númeroDaSala) {
    return new Sala(númeroDaSala);
  }

  public ParedeIF criaParede() {
    return new Parede();
  }

  public PortaIF criaPorta(SalaIF sala1, SalaIF sala2) {
    return new Porta(sala1, sala2);
  }
}
public class Jogo implements JogoIF {
  // Observe que essa função não tem new: ela usa uma Abstract Factory
  // Esta é a *única* diferença com relação à versão original
  // Observe como montaLabirinto acessa a factory (através de um singleton)
  public LabirintoIF montaLabirinto(FactoryDeLabirintoIF factory) {
    LabirintoIF umLabirinto = factory.criaLabirinto();
    SalaIF sala1 = factory.criaSala(1);
    SalaIF sala2 = factory.criaSala(2);
    PortaIF aPorta = factory.criaPorta(sala1, sala2);

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

    sala1.setVizinho(NORTE, factory.criaParede());
    sala1.setVizinho(LESTE, aPorta);
    sala1.setVizinho(SUL, factory.criaParede());
    sala1.setVizinho(OESTE, factory.criaParede());

    sala2.setVizinho(NORTE, factory.criaParede());
    sala2.setVizinho(LESTE, factory.criaParede());
    sala2.setVizinho(SUL, factory.criaParede());
    sala2.setVizinho(OESTE, aPorta);

    return umLabirinto;
  }
}
public class FactoryDeLabirintoEncantado extends FactoryDeLabirinto {
  public SalaIF criaSala(int númeroDaSala) {
    return new salaEncantada(númeroDaSala, jogaEncantamento());
  }
  public PortaIF criaPorta(SalaIF sala1, SalaIF sala2) {
    return new portaPrecisandoDeEncantamento(sala1, sala2);
  }
  protected EncantamentoIF jogaEncantamento() {
    ...
  }
}
public class FactoryDeLabirintoPerigoso extends FactoryDeLabirinto {
  public ParedeIF criaParede() {
    return new paredeDestruível();
  }
  public SalaIF criaSala(int númeroDaSala) {
    return new salaComBomba(númeroDaSala);
  }
}
  JogoIF umJogo = new Jogo();
  FactoryDeLabirinto factory = FactoryDeLabirinto.getInstance("perigoso"); 
  jogo.montaLabirinto(factory);

maze4.gif (8937 bytes)

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

Perguntas finais para discussão

programa