PROVER UMA INTEFACE PARA CRIAR UMA FAMÍLIA DE OBJETOS RELACIONADOS OU DEPENDENTES SEM ESPECIFICAR SUAS CLASSES CONCRETAS
TAMBÉM CHAMADO DE "KIT"
PARECE SEMELHANTE AO PADRÃO FACTORY METHOD, MAS
EM VEZ DO CLIENTE (QUE QUER CRIAR OBJETOS SEM SABER AS CLASSES EXATAS) CHAMAR UM MÉTODO DE CRIAÇÃO (FACTORY METHOD), ELE DE ALGUMA FORMA POSSUI UM OBJETO (UMA ABSTRACT FACTORY) E USA ESTE OBJETO PARA CHAMAR OS MÉTODOS DE CRIAÇÃO
ONDE FACTORY METHOD QUER QUE VOCÊ SEJA DIFERENTE (VIA HERANÇA) PARA CRIAR OBJETOS DIFERENTES, O ABSTRACT FACTORY QUER QUE VOCÊ TENHA ALGO DIFERENTE
SE ELE POSSUIR UMA REFERÊNCIA A UM ABSTRACT FACTORY DIFERENTE, TODA A CRIAÇÃO SERÁ DIFERENTE
O FATO DE TODOS OS MÉTODOS DE CRIAÇÃO ESTAREM NA MESMA SUBCLASSE DE UMA ABSTRACT FACTORY PERTMITE SATISFAZER A RESTRIÇÃO DE CRIAR APENAS OBJETOS RELACIONADOS OU DEPENDENTES
EXEMPLO: LOOK-AND-FEEL DE GUIs
PARA LOOK-AND-FEEL DIFERENTES (MOTIF, WINDOWS, MAC, PRESENTATION MANAGER, ETC.) TEMOS FORMAS DIFERENTES DE MANIPULAR JANELAS, SCROLL BARS, MENUS, ETC.
PARA CRIAR UMA APLICAÇÃO COM GUI QUE SUPORTE QUALQUER LOOK-AND-FEEL, PRECISAMOS TER UMA FORMA SIMPLES DE CRIAR OBJETOS (RELACIONADOS) DE UMA MESMA FAMÍLIA
OS OBJETOS SÃO DEPENDENTES PORQUE NÃO POSSO CRIAR UMA JANELA ESTILO WINDOWS E UM MENU ESTILO MOTIF
JAVA JÁ RESOLVEU ESTE PROBLEMA INTERNAMENTE NO PACKAGE awt USANDO ABSTRACT FACTORY E VOCÊ NÃO PRECISA SE PREOCUPAR COM ISSO
PORÉM, VOCÊ PODERIA ESTAR USANDO C++ E PRECISARIA CUIDAR DISSO VOCÊ MESMO
UMA CLASSE (ABSTRATA) "ABSTRACT FACTORY" DEFINE UMA INTERFACE PARA CRIAR CADA TIPO DE OBJETO BÁSICO (WIDGETS NO LINGUAJAR GUI)
TAMBÉM TEM UMA CLASSE ABSTRATA PARA CADA TIPO DE WIDGET (WINDOW, SCROLL BAR, MENU, ...)
HÁ CLASSES CONCRETAS PARA IMPLEMENTAR CADA WIDGET EM CADA PLATAFORMA (LOOK-AND-FEEL)
CLIENTES CHAMAM A ABSTRACT FACTORY PARA CRIAR OBJETOS
UMA CONCRETE FACTORY CRIA OS OBJETOS CONCRETOS APROPRIADOS
VER O DIAGRAMA DE CLASSES ABAIXO
QUANDO USAR O PADRÃO ABSTRACT FACTORY?
QUANDO UM SISTEMA DEVE SER INDEPENDENTE DE COMO SEUS PRODUTOS SÃO CRIADOS, COMPOSTOS E REPRESENTADOS
QUANDO UM SISTEMA DEVE SER CONFIGURADO COM UMA ENTRE VÁRIAS FAMÍLIAS DE PRODUTOS
UMA FAMÍLIA DE PRODUTOS RELACIONADOS FOI PROJETADA PARA USO CONJUNTO E VOCÊ DEVE IMPLEMENTAR ESSA RESTRIÇÃO
VOCÊ QUER FORNECER UMA BIBLIOTECA DE CLASSES E QUER REVELAR SUA INTERFACE E NÃO SUA IMPLEMENTAÇÃO
NÃO PERMITA PORTANTO QUE OBJETOS SEJAM DIRETAMENTE CRIADOS
ESTRUTURA GENÉRICA
EXERCÍCIO PARA CADA: REDESENHE O DIAGRAMA PARA USAR INTERFACES
PARTICIPANTES
FactoryAbstrata (WidgetFactory)
DEFINE UMA INTERFACE PARA AS OPERAÇõES QUE CRIAM OBJETOS COMO PRODUTOS ABSTRATOS
FactoryConcreta (MotifWidgetFactory, WindowsWidgetFactory)
IMPLEMENTA AS OPERAÇÕES PARA CRIAR OBJETOS PARA PRODUTOS CONCRETOS
ProdutoAbstrato (Window, ScrollBar)
DEFINE UMA INTERFACE PARA OBJETOS DE UM TIPO
ProdutoConcreto (MotifWindow, MotifScrollBar)
DEFINE UM OBJETO PRODUTO A SER CRIADO PELA FactoryConcreta CORRESPONDENTE
IMPLEMENTA A INTERFACE DE ProdutoAbstrato
Cliente
USA APENAS INTERFACES DEFINIDAS POR FactoryAbstrata E ProdutoAbstrato
COLABORAÇÕES ENTRE OBJETOS
NORMALMENTE UMA ÚNICA INSTÂNCIA DE UMA CLASSE FactoryConcreta É CRIADA EM TEMPO DE EXECUÇÃO
ESSA FactoryConcreta CRIA OBJETOS TENDO UMA IMPLEMENTAÇÃO PARTICULAR
PARA CRIAR PRODUTOS DIFERENTES, CLIENTES DEVEM USAR UMA FactoryConcreta DIFERENTE
FactoryAbstrata DEPENDE DE SUAS SUBCLASSES FactoryConcreta PARA CRIAR OBJETOS DE PRODUTOS
CONSEQUÊNCIAS DO USO DO PADRÃO ABSTRACT FACTORY
O PADRÃO ISOLA CLASSES CONCRETAS
UMA FACTORY ENCAPSULA A RESPONSABILIDADE E O PROCESSO DE CRIAÇÃO DE OBJETOS DE PRODUTOS
ISOLA CLIENTES DAS CLASSES DE IMPLEMENTAÇÃO
O CLIENTE MANIPULA INSTÂNCIAS ATRAVÉS DE SUAS INTERFACES ABSTRATAS
FACILITA O CÂMBIO DE FAMÍLIAS DE PRODUTOS
A CLASSE DA FactoryConcreta SÓ APARECE EM UM LUGAR: ONDE ELA É INSTANCIADA
UMA MUDANÇA NUMA ÚNICA LINHA DE CÓDIGO PODE SER SUFICIENTE PARA MUDAR A FactoryConcreta QUE A APLICAÇÃO USA
A FAMÍLIA INTEIRA DE PRODUTOS MUDA DE UMA VEZ
PROMOVE A CONSISTÊNCIA ENTRE PRODUTOS
PRODUTOS DE UMA DETERMINADA FAMÍLIA DEVEM FUNCIONAR CONJUNTAMENTE E NÃO MISTURADOS COM PRODUTOS DE OUTRA FAMÍLIA
O PADRÃO PERMITE IMPLEMENTAR ESTA RESTRIÇÃO COM FACILIDADE
DO LADO NEGATIVO: DAR SUPORTE A NOVOS TIPOS DE PRODUTOS É DIFÍCIL
O MOTIVO É QUE A FactoryAbstrata FIXA O CONJUNTO DE PRODUTOS QUE PODEM SER CRIADOS
DAR SUPORTE A MAIS PRODUTOS FORÇA A EXTENSÃO DA INTERFACE DA FACTORY O QUE ENVOLVE MUDANÇAS NA FactoryAbstrata E EM TODAS SUAS SUBCLASSES FactoryConcreta
CONSIDERAÇÕES DE IMPLEMENTAÇÃO
FACTORY COMO PADRÃO SINGLETON
UMA APLICAÇÃO NORMALMENTE SÓ PRECISA DE UMA ÚNICA INSTÂNCIA DE UMA FactoryConcreta POR FAMÍLIA DE PRODUTOS
O PADRÃO SINGLETON AJUDA A CONTROLAR A INSTÂNCIA ÚNICA
CRIAÇÃO DOS PRODUTOS
A FactoryAbstrata APENAS DEFINE A INTERFACE DE CRIAÇÃO
QUEM CRIA OS OBJETOS SÃO AS FactoryConcreta
TAIS SUBCLASSES SÃO FREQUENTEMENTE IMPLEMENTADAS USANDO O PADRÃO FACTORY METHOD
UMA FactoryConcreta FAZ OVERRIDE DO FACTORY METHOD DE CADA PRODUTO
EXEMPLO DE CÓDIGO: CRIAÇÃO DE LABIRINTOS
TODOS OS FACTORY METHODS DO PADRÃO ANTERIOR SAEM DA CLASSE Jogo E ENTRAM NA FACTORY ABSTRATA FactoryDeLabirinto
TAMBÉM POSSUEM UM DEFAULT, O QUE SIGNIFICA QUE FactoryDeLabirinto TAMBÉM É UMA FACTORY CONCRETA
class FactoryDeLabirinto { // factory methods // tem default para as factory methods 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); } }
A NOVA VERSÃO DE criaLabirinto RECEBE UM FactoryDeLabirinto COMO PARÂMETRO E CRIA UM LABIRINTO
class Jogo { // Observe que essa função não tem new: ela usa // um abstract factory recebido como parâmetro // Esta é a *única* diferença com relação à versão original public Labirinto criaLabirinto(FactoryDeLabirinto factory) { Labirinto umLabirinto = factory.criaLabirinto(); Sala sala1 = factory.criaSala(1); Sala sala2 = factory.criaSala(2); Porta 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; } }
PARA CRIAR UM LABIRINTO ENCANTADO, CRIAMOS UMA FACTORY CONCRETA COMO SUBCLASSE DE FactoryDeLabirinto
class FactoryDeLabirintoEncantado extends FactoryDeLabirinto { 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() { ... } }
PARA CRIAR UM LABIRINTO PERIGOSO, CRIAMOS UMA OUTRA FACTORY CONCRETA COMO SUBCLASSE DE FactoryDeLabirinto
class FactoryDeLabirintoPerigoso extends FactoryDeLabirinto { public Parede criaParede() { return new ParedeDestruível(); } public Sala criaSala(int númeroDaSala) { return new SalaComBomba(númeroDaSala); } }
FINALMENTE, PODEMOS JOGAR:
Jogo umJogo = new Jogo(); FactoryDeLabirintoPerigoso factory = new FactoryDeLabirintoPerigoso(); jogo.criaLabirinto( factory );
PODERÍAMOS JOGAR UM JOGO ENCANTADO COM UMA MUDANÇA MUITO SIMPLES AO CÓDIGO ACIMA
O DIAGRAMA DE OBJETOS TEM UM OBJETO A MAIS COMPARADO COM A VERSÃO ORIGINAL