Você está na página 1de 4

Mo na massa: Abstract Factory

18 09 2011
Falamos no post anterior sobre o famoso Factory Method, agora vamos demonstrar o
Abstract Factory!
Problema
Vamos utilizar como o problema o mesmo discutido no post sobre o Factory Method.
Queremos representar um sistema que, dado um conjunto de carros deve manipul-los.
A diferena que, desta vez, precisamos agrupar os carros em conjuntos. A ideia de
conjuntos agrupar objetos que tem comportamentos parecidos. Para exemplificar veja
como os objetos devem ser organizados:
Sedan:
Siena Fiat
Fiesta Sedan Ford
Popular:
Palio Fiat
Fiesta Ford
Ou seja, agora precisamos agrupar um conjunto de carros Sedan e outro conjunto de
carros Popular para cada uma das fbricas.
Se considerarmos os carros Sedan como um produto, poderamos criar uma classe
produto para cada novo carro e, consequentemente uma classe fbrica para cada novo
produto.
O problema que, desta forma no teramos a ideia de agrupamento dos produtos. Por
exemplo, para criar os carros da Fiat precisaramos de uma fbrica de carros populares
da Fiat e outra fbrica de carros sedan da Fiat. Essa separao dificultaria tratar os
carros de uma mesma marca.
Ento surge o padro Abstract Factory, que leva a mesma ideia do Factory Method para
um nvel mais alto.
Abstract Factory
Vejamos a inteno do Padro Abstract Factory:
Fornecer uma interface para criao de famlias de objetos relacionados ou
dependentes sem especificar suas classes concretas.[1]
Ento, de acordo com a descrio da inteno do padro, ns poderemos criar famlias
de objetos, no nosso exemplo seriam a famlia de carros Sedan e a famlia de carros
Populares. Sem mais demora vamos ao cdigo.
Inicialmente vamos escrever a classe interface para criao de Fbricas. Cada fabrica
vai criar um objeto de cada tipo, ou seja, para o nosso exemplo, precisaremos de dois
mtodos fbrica, um para carros Sedan e outro para carros Populares:
1
2
3
4
publ i c i nt er f ace Fabr i caDeCar r o {
Car r oSedan cr i ar Car r oSedan( ) ;
Car r oPopul ar cr i ar Car r oPopul ar ( ) ;
}
E agora vamos escrever as classes que vo criar os carros de fato:
1
2
3
4
5
6
7
8
9
10
11
12
13
publ i c cl ass Fabr i caFi at i mpl ement s Fabr i caDeCar r o {

@Over r i de
publ i c Car r oSedan cr i ar Car r oSedan( ) {
r et ur n new Si ena( ) ;
}

@Over r i de
publ i c Car r oPopul ar cr i ar Car r oPopul ar ( ) {
r et ur n new Pal i o( ) ;
}

}
Pronto! Todas as outras fbricas precisam apenas implementar esta pequena interface.
Vamos ento para o lado do produto. Como j comentamos os produtos so divididos
em dois grupos, Sedan e Popular, em que cada um deles possui um conjunto de
atributos e mtodos prprios. Para o nosso exemplo vamos considerar que existe um
mtodo para exibir informaes de um carro Sedan e outro para exibir informaes de
carros Populares. As interfaces seriam assim:
1
2
3
publ i c i nt er f ace Car r oPopul ar {
voi d exi bi r I nf oPopul ar ( ) ;
}
1
2
3
publ i c i nt er f ace Car r oSedan {
voi d exi bi r I nf oSedan( ) ;
}
Apesar de os mtodos basicamente executarem a mesma operao, diferindo apenas no
nome, suponha que os carros Populares esto em um banco de dados e os carros Sedan
em outros, assim cada mtodo precisaria criar sua prpria conexo.
Agora vamos ver os produtos concretos:
1
publ i c cl ass Pal i o i mpl ement s Car r oPopul ar {
2
3
4
5
6
7
8

@Over r i de
publ i c voi d exi bi r I nf oPopul ar ( ) {
Syst em. out . pr i nt l n( "Model o: Pal i o\ nFbr i ca:
Fi at \ nCat egor i a: Popul ar ") ;
}

}
1
2
3
4
5
6
7
8
publ i c cl ass Si ena i mpl ement s Car r oSedan {

@Over r i de
publ i c voi d exi bi r I nf oSedan( ) {
Syst em. out . pr i nt l n( "Model o: Si ena\ nFbr i ca:
Fi at \ nCat egor i a: Sedan") ;
}

}
Pronto, definido as fbricas e os produtos vamos analisar o cdigo cliente:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
publ i c st at i c voi d mai n( St r i ng[ ] ar gs) {
Fabr i caDeCar r o f abr i ca = new Fabr i caFi at ( ) ;
Car r oSedan sedan = f abr i ca. cr i ar Car r oSedan( ) ;
Car r oPopul ar popul ar = f abr i ca. cr i ar Car r oPopul ar ( ) ;
sedan. exi bi r I nf oSedan( ) ;
Syst em. out . pr i nt l n( ) ;
popul ar . exi bi r I nf oPopul ar ( ) ;
Syst em. out . pr i nt l n( ) ;

f abr i ca = new Fabr i caFor d( ) ;
sedan = f abr i ca. cr i ar Car r oSedan( ) ;
popul ar = f abr i ca. cr i ar Car r oPopul ar ( ) ;
sedan. exi bi r I nf oSedan( ) ;
Syst em. out . pr i nt l n( ) ;
popul ar . exi bi r I nf oPopul ar ( ) ;
}
Perceba que criamos uma referncia para uma fbrica abstrata e jogamos nela qualquer
fbrica, de acordo com o que necessitamos. De maneira semelhante criamos referncias
para um carro Popular e para um carro Sedan, e de acordo com nossas necessidades
fomos utilizando os carros dos fabricantes.
Essa a estrutura do projeto de fbricas de carros Sedan e Popular:

Um pouco de teoria
Como voc pode notar, este padro sofre do mesmo problema do Factory Method, ou
seja criamos uma estrutura muito grande de classes e interfaces para resolver o
problema de criao de objetos. No entanto, segundo o princpio da Segregao de
Interface [2] isto uma coisa boa, pois o nosso cdigo cliente fica dependendo de
interfaces simples e pequenas ao invs de depender de uma interface grande e que nem
todos os mtodos seria utilizados.
Para exemplificar suponha que crissemos apenas uma interface para carros, nela
precisaramos definir os mtodos de exibir informaes tanto para Populares quanto
para Sedan. O porblema que, dado um carro qualquer no d pra saber se ele um
sedan ou um popular. E o que fazer para implementar o mtodo de Populares em carros
Sedan (e vice-versa)?
Ou seja, criar vrias interfaces simples e pequenas melhor do que uma interface faz-
tudo. Ento qual o problema com o padro?
Pense como seria se tivssemos que inserir uma nova famlia de produtos, por exemplo
Sedan de Luxo. Do lado dos produtos apenas definiramos a interface e
implementaramos os produtos. Mas do lado das fbricas ser necessrio inserir um
novo mtodo de criao em TODAS as fbricas. Tudo bem que o mtodo de criao no
exemplo bem simples, ento seria apenas tedioso escrever os cdigos para todas as
classes.
Cdigo fonte completo
O cdigo completo pode ser baixado no seguinte repositrio Git:
https://github.com/MarcosX/Padr-es-de-Projeto.
Os arquivos esto como um projeto do eclipse, ento basta colocar no seu Workspace e
fazer o import.
Se gostou do post compartilhe com seus amigos e colegas, seno, comente o que pode
ser melhorado. Encontrou algum erro no cdigo? Comente tambm. Possui alguma
outra opinio ou alguma informao adicional? Comenta ai!

Você também pode gostar