Abstract Factory Pattern SISMO - Sistemas e Mobilidade http://www.sismo.deinf.ufma.br Departamento de Informática / UFMA Junho de 2008
Comandar uma franquia não é bolinho Estava tudo muito bom com a franquia PizzaRute, mas... Alguns franqueados resolveram aumentar as margens de lucro usando ingredientes mais baratos e de baixa qualidade É necessário garantir consistência na qualidade os ingredientes usados pelas franquias Como atacar esse problema?
Mantendo a consistência dos ingredientes A idéia é criar uma fábria (real) para produzir os ingredientes para todas as franquias A fábrica deve produzir e enviar os ingredientes aos franqueados Porém, existe um problema. Os ingredientes das pizzas são essencialmente os mesmos em cada região, mas existem variações específicas das diferentes regiões. Por exemplo, o cheiro verde da região sudeste tem salsa no lugar do coentro, o marisco em São Luis é diferente do marisco em São Paulo
Mantendo a consistência dos ingredientes II De um modo geral, cada região (e as franquias regionais) usam uma família de ingredientes específico Logo serão abertas novas franquias em Roraima e até no Caribe É necessário definir um modo de lidar com essas diferentes famílias de ingredientes
A fábrica de ingredientes A fábrica será responsável pela criação de Famílias de Ingredientes A idéia de criar famílias de ingredientes é manter a consistência do conjunto de ingredientes que satisfaz o gosto dos clientes da região Não se deve permitir, por exemplo, misturar ingredientes da franquia gaucha com ingredientes da franquia bahiana
A Fábrica de Ingredientes Figura: Interface para a Fábrica de Ingredientes
Implementando Fábricas de Ingredientes Figura: Fábrica de Ingredientes da Franquia de São Paulo
Como fica a classe Pizza? Figura: A nova classe Pizza
Uma Classe Pizza concreta Figura: Uma classe concreta Pizza de Mussarela
Analisando o código molho = ingredientefactory.createmolho(); A fábrica de ingredientes agora é usada para produzir pizzas O tipo de ingrediente depende do tipo de fábrica usada Se usarmos uma fábrica de ingredientes de São Luis, ela produzirá um molho do tipo consumido em São Luis A pizza não sabe qual a fábrica que está sendo usada, desde que ela seja uma fábrica de ingredientes
Outra Classe Pizza concreta Figura: Uma classe concreta Pizza de Mariscos Em São Luis, o marisco pode ser sarnambi. Quem decide é a fábrica de ingredientes.
Como ficam as franquias? Figura: Uma classe concreta Franquia de São Paulo
Compare com a implementação Factory Method Figura: Uma classe concreta Franquia de São Paulo - Versão anterior
As Principais Mudanças Possibilitou-se a criação de uma família de ingredientes para pizzas pela introdução de uma novo tipo de fábrica chamada Abstract Factory Abstract Factory fornece uma interface para criar uma família de produtos No nosso exemplo, a família de produtos é formada por todos os ingredientes básicos de uma pizza (massa, queijo, molho, etc.), os quais sempre devem andar juntos, como uma família tradicional. O que muda é a implementação das famílias.
As Principais Mudanças II Da Abstract Factory derivamos fábricas concretas Cada fábrica de ingredientes cria diferentes implementações desses mesmos ingredientes ao implementar os métodos declarados na Abstract Factory Nosso código é separado dos produtos reais Se substituirmos as fábricas, obtemos famílias (implementações) diferentes dos mesmos produtos. O que resulta em pizzas diferentes.
Fazendo um pedido Precisamos inicialmente de uma franquia concreta PizzaRute sppizzarute = new SampaPizzaRute(); Agora que temos uma franquia, podemos fazer um pedido sppizzarute.pedidopizza( mussarela ); O método pedidopizza() chama o método createpizza() pizza = createpizza(tipo);
Fazendo um pedido - continuando No método createpizza(), a fábrica de ingredientes é passada para o construtor de Pizzas pizza = new PizzaMussarela(ingredientFactory); O método prepare(), implementado nas classes Pizza concretas, usa a fábrica de ingredientes para criar cada ingrediente da pizza, de acordo com a família dele massa = ingredientefactory.createmassa(); Finalmente, o método pedidopizza() chama os outros métodos da Pizza para terminar o pedido (pizza.asse(), pizza.corte(), etc)
O Padrão Abstract Factory Classificação: Propósito: Criacional / Escopo: Objetos Intenção: fornecer uma interface para criar famílias de objetos relacionados ou dependentes sem especificar suas classes concretas. aka: kit
Aplicabilidade Quando usar o padrão Um sistema não deve depender de como seus produtos são criados, compostos e representados Um sistema deve ser configurado como um produto de uma família de muitos produtos garantir que uma família de objetos-produto seja usada em conjunto, se foi projetada com esse fim
Estrutura Figura: Uma classe concreta AbstractFactory - Estrutura
Participantes AbstractFactory: declara interface para operações que criam objetos-produto abstratos ConcreteFactory: implementa operações que criam objetos-produto concretos AbstractProduct: declara interface para um tipo de objeto-produto ConcreteProduct: define um objeto-produto a ser criado pela fábrica concreta correspondente implementa a interface de AbstractProduct
Colaborações Normalmente uma única instância de uma classe ConcreteFactory é criada em tempo de execução AbstractFactory adia a criação dos objetos produto para a classe ConcreteFactory
Consequências Isola as classes concretas (não aparecem no código do cliente) Facilita a troca de família de produtos Promove a harmonia entre produtos É difícil suportar novos tipos de produtos (exige mudar a classe AbstractFactory e todas as suas subclasses)
Mais um Exemplo Construção de interfaces de usuário que suportem diferentes estilos de interação, permitindo diferentes apresentações e comportamentos para os widgets de cada estilo As dependências entre as classes concretas de widgets também precisam ser garantidas e implementadas
Estrutura do exemplo Figura: Uma classe concreta Famílias de Widgets