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.
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
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 ?
R
rlanhellas
Estou “voando” um pouco ainda no conceito de Abstract Factory.
V
ViniGodoy
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
rlanhellas
Pode me dar um exemplo do Abstract Factory mais simples ? Essa do Game ficou ainda um pouco “obscuro”
V
ViniGodoy
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
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 factorypublicabstractclassCarro{publicabstractCarrocriarCarro();publicabstractvoidpintarCarro(Stringcor);}publicclassHondaextendsCarro{privateStringcor;publicCarrocriarCarro(){returnnewHonda();}publicvoidpintarCarro(Stringcor){this.cor=cor;}publicvoidacelerar(){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
rmendes08
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 factorypublicabstractclassCarro{publicabstractCarrocriarCarro();publicabstractvoidpintarCarro(Stringcor);}publicclassHondaextendsCarro{privateStringcor;publicCarrocriarCarro(){returnnewHonda();}publicvoidpintarCarro(Stringcor){this.cor=cor;}publicvoidacelerar(){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:
No caso o Factory Method é utilizado em conjunto com o Abstract Method correto ?
Por exemplo:
abstractclassWidgetFactory{publicstaticWidgetFactoryobterFactory(){if(Configuracao.obterInterfaceGraficaAtual()==Configuracao.MotifWidget){returnnewMotifWidgetFactory();}else{returnnewQtWidgetFactory();}}publicabstractBotaocriarBotao();}classMotifWidgetFactoryextendsWidgetFactory{publicBotaocriarBotao(){returnnewBotaoMotif();}}classQtWidgetFactoryextendsWidgetFactory{publicBotaocriarBotao(){returnnewBotaoQt();}}abstractclassBotao{publicabstractvoiddesenhar();}classBotaoMotifextendsBotao{publicvoiddesenhar(){System.out.println("Eu sou um botao Motif!");}}classBotaoQtextendsBotao{publicvoiddesenhar(){System.out.println("Eu sou um botao Qt!");}}publicclassCliente{publicstaticvoidmain(String[]args){WidgetFactoryfactory=WidgetFactory.obterFactory();Botaobotao=factory.criarBotao();botao.desenhar();}}
No exemplo acima ocorre o Factory Method quando fazemos
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
rmendes08
rlanhellas:
No caso o Factory Method é utilizado em conjunto com o Abstract Method correto ?
Por exemplo:
abstractclassWidgetFactory{publicstaticWidgetFactoryobterFactory(){if(Configuracao.obterInterfaceGraficaAtual()==Configuracao.MotifWidget){returnnewMotifWidgetFactory();}else{returnnewQtWidgetFactory();}}publicabstractBotaocriarBotao();}classMotifWidgetFactoryextendsWidgetFactory{publicBotaocriarBotao(){returnnewBotaoMotif();}}classQtWidgetFactoryextendsWidgetFactory{publicBotaocriarBotao(){returnnewBotaoQt();}}abstractclassBotao{publicabstractvoiddesenhar();}classBotaoMotifextendsBotao{publicvoiddesenhar(){System.out.println("Eu sou um botao Motif!");}}classBotaoQtextendsBotao{publicvoiddesenhar(){System.out.println("Eu sou um botao Qt!");}}publicclassCliente{publicstaticvoidmain(String[]args){WidgetFactoryfactory=WidgetFactory.obterFactory();Botaobotao=factory.criarBotao();botao.desenhar();}}
No exemplo acima ocorre o Factory Method quando fazemos
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
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.
R
rmendes08
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
rmendes08
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
rlanhellas
A classe que é cliente da fábrica (nesse caso um JFrame) pode utilizar tanto PessoaJuridica, Dentista ou Funcionario.
R
rlanhellas
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
rmendes08
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
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.
R
rmendes08
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
rlanhellas
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
rmendes08
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
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.
R
rmendes08
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.