Dúvida sobre Abstract Factory

23 respostas
R

Estou estudando os padrões de projeto Factory Method e Abstract Factory.

O Factory Method ficou bem claro que através de apenas 1 método você passa o parâmetro e ele cria o objeto de acordo com aquele parâmetro. Porém o Abstract Factory pelo que percebi é uma Fabrica de criar Fabricas, e ainda não consegui ver a utilidade disso, mesmo porque o Factory Method o faz de forma mais simples.

23 Respostas

V

O AbstractFactory é um objeto que contém um conjunto de fábricas de coisas relacionadas. Por exemplo, você tem um Game de pacman, e quer permitir a inclusão de skins nesse game. Você pode criar uma AbstractFactory assim:

public abstract class SceneFactory { public abstract PacmanView createPacmanView(); public abstract GhostView createGhostView(); public abstract FruitView createFruitView(); public abstract PillView createPillView(); public abstract WallView createWallView(); }

Se aguém quiser criar uma nova skin para seu game, basta agora implementar essa Factory abstrata. Por exemplo, você poderia querer ter um Pacman com o estilo do gótico:

Veja que para o programador de GothFactory, fica fácil saber todas as fábricas que precisam ser criadas, pois o AbstractFactory contém uma série de TemplateMethods, que são também FactoryMethods.

R

Então pelo que eu entendi o Abstract Factory serve apenas para definir uma Interface (contrato padrão) do que deve ser implementado, mas esse não é conceito de Classe Abstrata ou mesmo Interface ? Em que o Abstract Factory acrescenta nestes conceitos ?

R

Estou “voando” um pouco ainda no conceito de Abstract Factory.

V

rlanhellas:
Então pelo que eu entendi o Abstract Factory serve apenas para definir uma Interface (contrato padrão) do que deve ser implementado, mas esse não é conceito de Classe Abstrata ou mesmo Interface ? Em que o Abstract Factory acrescenta nestes conceitos ?

Não acrescenta nada aos conceitos, ela usa esses conceitos.
Não viaje muito. Muitos padrões são apenas dicas de como aplicar os conceitos para um propósito específico.

Nesse caso, o propósito é facilitar a definição de um conjunto de fábricas de objetos relacionados.

Outros padrões, como o Strategy, são simplesmente a implementação do conceito de polimorfismo. O padrão só ajuda a entender um propósito. No caso do Strategy, o de lembrar que uma classe pode se referir a um algoritmo ou a uma técnica, não somente a objetos do mundo real.

R

Pode me dar um exemplo do Abstract Factory mais simples ? Essa do Game ficou ainda um pouco “obscuro”

V

Você pode querer, por exemplo, que seu server possa escolher um entre vários algoritmos de criptografia.

Como vc sabe, é necessário ter uma classe que codifica a mensagem e outra que decodifica.

Você poderia ter uma AbstractFactory assim:

public abstract class CriptoProvider { public abstract Encoder createEncoder(); public abstract Decoder createDecoder(); }

E aí teria as implementações:

R

Bom, no código abaixo vou tentar demonstrar o uso do Abstract Factory junto com o Factory Method. Me diga se esta correto:

//Aqui aplico o abstract factory
 public abstract class Carro{
    public abstract Carro criarCarro();
    public abstract void pintarCarro(String cor);
 }

 public class Honda extends Carro{
    
    private String cor;
   
    public Carro criarCarro(){
             return new Honda();
      }

   public void pintarCarro(String cor){
      this.cor = cor;      
  }
  
  public void acelerar(){
     while(pisandoAceleador){
          acelerar();
     }
   }

}

Legal, defini acima uma classe abstrata Carro e uma classe concreta Honda. Posso chamar a implementação acima de Abstract Factory ?

R

rlanhellas:
Bom, no código abaixo vou tentar demonstrar o uso do Abstract Factory junto com o Factory Method. Me diga se esta correto:

//Aqui aplico o abstract factory
 public abstract class Carro{
    public abstract Carro criarCarro();
    public abstract void pintarCarro(String cor);
 }

 public class Honda extends Carro{
    
    private String cor;
   
    public Carro criarCarro(){
             return new Honda();
      }

   public void pintarCarro(String cor){
      this.cor = cor;      
  }
  
  public void acelerar(){
     while(pisandoAceleador){
          acelerar();
     }
   }

}

Legal, defini acima uma classe abstrata Carro e uma classe concreta Honda. Posso chamar a implementação acima de Abstract Factory ?

Não. Esse padrão é ainda é o Factory Method. A diferença entre estes dois padrões é que no caso do Factory Method, o cliente da fábrica é a própria classe abstrata, por exemplo:

abstract class Service<T>{
  pubic final void save(T obj){
     getDao().save(obj);
  }

  protected abstract DAO<T> getDao();
}

ou seja, a superclasse delega para uma classe filha a criação dos objetos que ela precisa;

No caso da AbstractFactory, além da possibilidade de servir de fábrica para vários tipos de objetos, ela é baseada em composição. O cliente da AbstractFactory não é uma superclasse de AbstractFactory, mas uma outra classe qualquer, por exemplo:

class WidgetFactory{
  getButton();
  getTextInput();
  getListBox();
}

class FormularioCliente extends Formulario{
  
  FormularioCliente(WidgetFactory factory){
      Button bt = factory.getButton();
      bt.setText("Salvar");
      add(bt);
  }
}
R

No caso o Factory Method é utilizado em conjunto com o Abstract Method correto ?

Por exemplo:

abstract class WidgetFactory
 {
     public static WidgetFactory obterFactory()
     {
 
         if( Configuracao.obterInterfaceGraficaAtual() == Configuracao.MotifWidget )
         {
             return new MotifWidgetFactory();
         }
         else
         {
             return new QtWidgetFactory();
         }
    }
 
    public abstract Botao criarBotao();
 }
 
 class MotifWidgetFactory extends WidgetFactory
 {
     public Botao criarBotao()  {
         return new BotaoMotif();
     }
 }
 
 class QtWidgetFactory extends WidgetFactory
 {
     public Botao criarBotao()  {
         return new BotaoQt();
     }
  }
 
 abstract class Botao
 {
     public abstract void desenhar();
 }
 
 class BotaoMotif extends Botao
 {
     public void desenhar()  {
        System.out.println("Eu sou um botao Motif!");
     }
 }
 
 class BotaoQt extends Botao
 {
     public void desenhar()  {
        System.out.println("Eu sou um botao Qt!");
     }
 }
 
 public class Cliente
 {
     public static void main(String[] args)
     {
         WidgetFactory factory = WidgetFactory.obterFactory();
 
         Botao botao = factory.criarBotao();
         botao.desenhar();
     }
 }

No exemplo acima ocorre o Factory Method quando fazemos

if( Configuracao.obterInterfaceGraficaAtual() == Configuracao.MotifWidget )
         {
             return new MotifWidgetFactory();
         }
         else
         {
             return new QtWidgetFactory();
         }

O conjunto todo é o Abstract Factory visto que a fabrica abstrata WidgetFactory diz o que as suas fabricas concretas devem implementar, ou seja, a função do abstract factory é dizer para suas fabricas filhas o que deve ser implementado mas não como deve ser implementado. Assim sendo quando o usuário for instanciar um MotifWidgetFactory ele não chama diretamente o MotifWidgetFactory, mas chama o WidgetFactory que criará um MotifWidgetFactory. Certo ? Isso ae é uma mistura de Factory Method com Abstract Factory.

R

rlanhellas:
No caso o Factory Method é utilizado em conjunto com o Abstract Method correto ?

Por exemplo:

abstract class WidgetFactory
 {
     public static WidgetFactory obterFactory()
     {
 
         if( Configuracao.obterInterfaceGraficaAtual() == Configuracao.MotifWidget )
         {
             return new MotifWidgetFactory();
         }
         else
         {
             return new QtWidgetFactory();
         }
    }
 
    public abstract Botao criarBotao();
 }
 
 class MotifWidgetFactory extends WidgetFactory
 {
     public Botao criarBotao()  {
         return new BotaoMotif();
     }
 }
 
 class QtWidgetFactory extends WidgetFactory
 {
     public Botao criarBotao()  {
         return new BotaoQt();
     }
  }
 
 abstract class Botao
 {
     public abstract void desenhar();
 }
 
 class BotaoMotif extends Botao
 {
     public void desenhar()  {
        System.out.println("Eu sou um botao Motif!");
     }
 }
 
 class BotaoQt extends Botao
 {
     public void desenhar()  {
        System.out.println("Eu sou um botao Qt!");
     }
 }
 
 public class Cliente
 {
     public static void main(String[] args)
     {
         WidgetFactory factory = WidgetFactory.obterFactory();
 
         Botao botao = factory.criarBotao();
         botao.desenhar();
     }
 }

No exemplo acima ocorre o Factory Method quando fazemos

if( Configuracao.obterInterfaceGraficaAtual() == Configuracao.MotifWidget )
         {
             return new MotifWidgetFactory();
         }
         else
         {
             return new QtWidgetFactory();
         }

O conjunto todo é o Abstract Factory visto que a fabrica abstrata WidgetFactory diz o que as suas fabricas concretas devem implementar, ou seja, a função do abstract factory é dizer para suas fabricas filhas o que deve ser implementado mas não como deve ser implementado. Assim sendo quando o usuário for instanciar um MotifWidgetFactory ele não chama diretamente o MotifWidgetFactory, mas chama o WidgetFactory que criará um MotifWidgetFactory. Certo ? Isso ae é uma mistura de Factory Method com Abstract Factory.

Quase isso … não existe nada que proíba você combinar os padrões, por outro lado, também não tem nada que o obrigue. Como eu disse, são dois padrões diferentes que são usados em momentos diferentes;

Uma implementação de AbstractFactory não caracteriza os métodos da AbstractFactory como FactoryMethod’s. Isso porque a AbstractFactory não vai usar os objetos criados por suas implementações, elas serão usadas por classes que são clientes da AbstractFactory. O caso do Factory Method é diferente, a classe que declara o Factory Method é a mesma classe que vai usá-lo, porém, ela apenas delega a criação para uma subclasse.

R

Reabrindo o tópico, surgiu um exemplo legal para tentar aplicar o Abstract Factory e gostaria que vocês me ajudassem:

Tenho uma Classe Pessoa que se especializa em PessoaFisica e PessoaJuridica. A PessoaFisica ainda pode se especializar em Funcionario ou Dentista. Como ficaria isso aplicando Abstract Factory e Factory Method ?.

Sendo que eu quero chamar apenas 1 fabrica capaz de criar dentista, funcionario ou pessoaJuridica conforme o parametro passado.

R

rlanhellas:
Reabrindo o tópico, surgiu um exemplo legal para tentar aplicar o Abstract Factory e gostaria que vocês me ajudassem:

Tenho uma Classe Pessoa que se especializa em PessoaFisica e PessoaJuridica. A PessoaFisica ainda pode se especializar em Funcionario ou Dentista. Como ficaria isso aplicando Abstract Factory e Factory Method ?.

Sendo que eu quero chamar apenas 1 fabrica capaz de criar dentista, funcionario ou pessoaJuridica conforme o parametro passado.

e a pergunta de 1 milhão de reaishmmm …

A classe que é o cliente da fábrica trabalha apenas com o tipo mais abstrato ?

R

Outra dica: já vi 4 níveis de profundidade na sua hierarquia de classes, será que não cabe uma composição ai não ? Será que ao invés de dizer que Funcionario É-UM Dentista não ficaria melhor dizer que Funcionario TEM-UMA ProfissaoDentista ?

R

A classe que é cliente da fábrica (nesse caso um JFrame) pode utilizar tanto PessoaJuridica, Dentista ou Funcionario.

R

rmendes08, acontece que o dentista possui alguns campos que o funcionário não tem como: CRO, Porcentagem de Ganho, Formação (Universidade) e etc…

R

Tudo bem, mas a minha pergunta é: o tipo da variável usada é sempre o tipo mais abstrato, Pessoa ? Porque não adianta nada você abstrair a criação do objeto para depois usar instanceof em cima da variável.

R

Verdade, nem sempre vou usar apenas Pessoa, na verdade são raras as vezes que vou usar Pessoa, vou utilizar mais : PessoaJuridica, Dentista ou Funcionario.

Mas não deixarei a classe PessoaFisica e Pessoa como abstrata pois poderemos utilizar ela em alguma parte da aplicação.

R

Tudo bem, a princípio, tanto herança quanto composição resolvem o problema de adicionar campos que não são comuns a qualquer funcionário. O problema é que ao utilizar herança você aumenta o acoplamento entre objetos. Um Funcionario, que é criado como Dentista por exemplo, nunca poderá ser outra coisa.

Agora, falando em termos mais objetivos. Se você estiver montando um cadastro, utlizar muitos níveis de herança pode dificultar o seu projeto. Por exemplo, sempre que você tiver que cadastrar um Dentista, sua tela precisará de todos os campos de Pessoa, PessoaFisica e Funcionario; E isso pode ser terrível em termos de UX (User eXperience). Por outro lado, se você aplica composição você pode criar uma tela apenas para cadastro de Pessoa, uma tela para o cadastro de Funcionario e outra para o cadastro de Dentista, bastando apenas que você faça a ligação entre as entidades e compondo os objetos necessários.

R

não não, quando você diz: “sempre que você tiver que cadastrar um Dentista, sua tela precisará de todos os campos de Pessoa, PessoaFisica e Funcionario”.

Dentista não herda de funcionario, ele herda de PessoaFisica.

R

rlanhellas:
Verdade, nem sempre vou usar apenas Pessoa, na verdade são raras as vezes que vou usar Pessoa, vou utilizar mais : PessoaJuridica, Dentista ou Funcionario.

Mas não deixarei a classe PessoaFisica e Pessoa como abstrata pois poderemos utilizar ela em alguma parte da aplicação.

Pois é, então não tem sentido em você abstrair a criação desses objetos. Por exemplo, se você tiver uma tela “Cadastro de Dentista”, é mais simples e elegante chamar new Dentista() logo de uma vez e setar os campos apropriados. Do contrário, você teria que chamar a fábrica, chamar o getPessoa(TipoPessoa.DENTISTA) e ao receber o objeto você teria que fazer um cast Dentista d = (Dentista) pesssoa;

R

Entedi. Não precisamos do Abstract Factory.

Mas fiquei na dúvida sobre a modelagem:

1ª Opção - Classe PessoaFisica extends Pessoa. Sendo que pessoa fisica terá os atributos de Dentista e Funcionario, com um discriminator para dizer se é D (dentista) ou F (FUncionario). Sendo uma tabela pessoa_fisica

2 ª - Opcao - Classe PEssoaFisica extends Pessoa. Funcionario extends PessoaFisica e Dentista extends PessoaFisica. Sendo uma tabela para Dentista e outra para Funcionario.

R

rlanhellas:
Entedi. Não precisamos do Abstract Factory.

Mas fiquei na dúvida sobre a modelagem:

1ª Opção - Classe PessoaFisica extends Pessoa. Sendo que pessoa fisica terá os atributos de Dentista e Funcionario, com um discriminator para dizer se é D (dentista) ou F (FUncionario). Sendo uma tabela pessoa_fisica

2 ª - Opcao - Classe PEssoaFisica extends Pessoa. Funcionario extends PessoaFisica e Dentista extends PessoaFisica. Sendo uma tabela para Dentista e outra para Funcionario.

Eu apostaria na 2a opção sem dúvida. Mas ao invés de usar herança eu usaria composição, do tipo Funcionario TEM-UMA PessoaFisica e Dentista TEM-UMA PessoaFisica. Pode soar estranho mas faz sentido.

R

Porque composição ? Não entendi a relação;

Criado 17 de julho de 2013
Ultima resposta 18 de jul. de 2013
Respostas 23
Participantes 3