• Nenhum resultado encontrado

FactoryMethod 20101

N/A
N/A
Protected

Academic year: 2021

Share "FactoryMethod 20101"

Copied!
7
0
0

Texto

(1)

Padrões de Projeto

Factory Method

Fábio Gondim

Período: 2010.1

“Um projeto que não leva em

consideração a possibilidade

de mudanças está sujeito ao

risco de uma grande

reformulação no futuro.”

[GoF]

“Especificar um nome de uma classe

quando cria um objeto faz com que

você se comprometa com uma

particular implementação, em vez de

se comprometer com uma determinada

interface. Este compromisso pode

complicar futuras mudanças.

Para

evitá-lo, crie objetos indiretamente

.”

[GoF]

Factory Method

Veremos um exemplo, passo-a-passo,

adaptado do livro Head First - Design

Patterns, de Eric Freeman e Elisabeth

Freeman, para compreender a motivação

e utilização do padrão. O exemplo mostra

a evolução de uma modelagem para um

sistema hipotético de uma pizzaria.

public classPizzaria{ public Pizza pedirPizza() {

Pizzapizza = new Pizza(); pizza.preparar(); pizza.assar(); pizza.fatiar(); pizza.embalar(); returnpizza; } }

No início era apenas uma pequena pizzaria...

public Pizza pedirPizza(String tipo) {

Pizza pizza= null; if (tipo.equals(“Mussarela”)) {

pizza = newPizzaMussarela(); } else if (tipo.equals(“Calabresa”)) {

pizza = newPizzaCalabresa(); } else if (tipo.equals(“Grega”)) {

pizza = newPizzaGrega(); } pizza.preparar(); pizza.assar(); pizza.fatiar(); pizza.embalar(); returnpizza; }

... que certamente não prosperaria com apenas um tipo de pizza! Pizza passa a ser abstrata e surgem subtipos.

(2)

public Pizza pedirPizza(String tipo) { Pizza pizza= null;

if (tipo.equals("Mussarela")) { pizza = newPizzaMussarela(); } else if (tipo.equals("Calabresa")) { pizza = newPizzaCalabresa(); } else if (tipo.equals(“Grega")) {

pizza = new PizzaGrega(); } pizza.preparar(); pizza.assar(); pizza.fatiar(); pizza.embalar(); returnpizza; }

Certamente surgiram mudanças! Tipos foram eliminados...

A pizza grega não estava tendo saída.

public Pizza pedirPizza(String tipo) { Pizza pizza = null;

if (tipo.equals("Mussarela")) { pizza = newPizzaMussarela(); } else if (tipo.equals("Calabresa")) { pizza = new PizzaCalabresa(); } else if (tipo.equals(“Portuguesa")) {

pizza = newPizzaPortuguesa(); } else if (tipo.equals(“Napolitana")) {

pizza = newPizzaNapolitana(); } else if (tipo.equals(“Marguerita")) { pizza = newPizzaMarguerita(); }

//... }

... e novos tipos foram criados.

A concorrência lançava novos produtos e a pizzaria não queria ser ultrapassada!

public Pizza pedirPizza(String tipo) { Pizza pizza = null;

if (tipo.equals("Mussarela")) {

pizza = new PizzaMussarela(); } else if (tipo.equals("Calabresa")) { pizza = new PizzaCalabresa(); } else if (tipo.equals(“Grega")) {

pizza = new PizzaGrega(); } pizza.preparar(); pizza.assar(); pizza.fatiar(); pizza.embalar(); return pizza; }

Muitas mudanças estão ocorrendo aqui. Vamos separar o que varia e encapsular a criação de objetos.

public classSimplePizzaFactory{ public Pizza criarPizza(String tipo){

Pizza pizza= null;

if (tipo.equals("Mussarela")) { pizza = newPizzaMussarela(); } else if (tipo.equals("Calabresa")) { pizza = newPizzaCalabresa(); } else if (tipo.equals("Portuguesa")) {

pizza = newPizzaPortuguesa(); } else if (tipo.equals("Napolitana")) { pizza = newPizzaNapolitana(); } else if (tipo.equals("Marguerita")) { pizza = newPizzaMarguerita(); }

returnpizza; }

}

A classe SimplePizzaFactory será responsável pelo que varia: criação dos objetos.

public class Pizzaria {

// Nossa pizzaria agora contém uma fabrica SimplePizzaFactory fabrica;

public Pizzaria(SimplePizzaFactory fabrica) { this.fabrica = fabrica;

}

public static void main(String[] args) {

Pizzaria pizzaria = new Pizzaria(new SimplePizzaFactory()); Pizza pizza = pizzaria.pedirPizza("Mussarela");

}

public Pizza pedirPizza(String tipo) { Pizza pizza = null;

pizza = fabrica.criarPizza(tipo); pizza.preparar(); pizza.assar(); pizza.fatiar(); pizza.embalar(); return pizza; }

A nossa pizzaria contará, agora, com uma SimplePizzaFactoryque será responsável pela criação dos objetos.

“...ao encapsular a criação de pizzas em uma

classe, temos apenas um local para fazer

modificações quando a implementação é

alterada...

...uma coisa a ser lembrada é que a

SimplePizzaFactory pode ter muitos clientes...

... alguns desenvolvedores confundem a

Fábrica Simples com o ‘Padrão Fábrica’...

... a Fábrica Simples não é realmente um

Padrão de Projeto... Mas é muito usada...”

(3)

Mas o mundo não pára. O negócio continuou crescendo e transformou-se em franchising. Inicialmente são dois franqueados.

Os franqueados querem adaptar o cardápio

e a forma de preparo às preferências de

seus clientes:

• A preferência varia em cada região. O gosto da

população local muda e as franquias querem

oferecer estilos diferentes de pizza. Em um local

a massa deverá ser fina, no outro preferem

massa mais grossa, uns preferem pouco molho

com tempero forte, outros mais molho com

tempero suave, uns querem muito queijo, outros

querem menos queijo, etc...

• O design terá que adaptar-se a seguinte

situação:

os franqueados devem seguir os métodos

assar, fatiar e embalar definidos pelo

franqueador mas terão, cada um, seu

próprio cardápio e forma de preparo da

massa e da cobertura (molho, queijo,

tempero, aplicações, etc.).

Desta forma ao invés de termos:

PizzaMussarela,

PizzaCalabresa,

etc;

Teremos:

PizzaMussarelaSaoPaulo

e

PizzaMussarelaRioDeJaneiro

,

PizzaCalabresaSaoPaulo

e

PizzaCalabresaRioDeJaneiro

,

etc.

Como localizar as atividades de confecção

de pizzas na classe Pizzaria dando aos

franqueados liberdade para ter seu próprio

estilo regional?

Como localizar as atividades de confecção

de pizzas na classe Pizzaria dando aos

franqueados liberdade para ter seu próprio

estilo regional?

• Uma estratégia é devolver o método

criarPizza() para a classe Pizzaria, mas desta

vez como um método

abstrato

, e depois criar

uma subclasse de Pizzaria para cada estilo

regional.

• Quando estudarmos o padrão Abstract Factory

(4)

O pedido será, então, definido na superclasse, mas

a criação ficará a critério das subclasses: cada

uma terá a sua própria implementação do método

criarPizza() que será

abstrato na superclasse

.

public

abstract

class Pizzaria {

public Pizza pedirPizza(String

tipo

) {

Pizza pizza = null;

pizza =

criarPizza(

tipo

)

;

pizza.preparar();

pizza.assar();

pizza.fatiar();

pizza.embalar();

return pizza;

}

public

abstract

Pizza

criarPizza(

String

tipo

)

;

}

O método criarPizza()

é um Factory Method!

abstract Produto

factoryMethod(String

tipo)

Um método fábrica é abstrato, de modo que as subclasses têm que lidar com a criação de objetos.

Um método fábrica retorna um produto que geralmente é usado dentro de métodos definidos na superclasse.

Um método fábrica pode ser parametrizado (ou não) para selecionar dentre diversas variações de um produto.

Um método fábrica isola o cliente que não precisa saber que tipo de Produto Concreto é realmente criado.

abstract

Pizza

criarPizza(

String

tipo);

Um método fábrica é abstrato, de

modo que as subclasses têm que lidar com a criação de objetos.

Um método fábrica retorna um produto que geralmente é usado dentro de métodos definidos na superclasse.

Um método fábrica pode ser parametrizado (ou não) para selecionar dentre diversas

Um método fábrica isola o cliente que não precisa saber que tipo de Produto Concreto é realmente criado.

public abstract classPizza{ String nome;

String massa; String molho;

ArrayList <String> aplicacoes= new ArrayList<String>(); public voidpreparar(){

System.out.println("Preparando " + nome);

System.out.println("Preparando a massa: " + massa); System.out.println("Adicionando molho: " + molho); System.out.println("Adicionando aplicações: "); for (String aplicacao: aplicacoes) {

System.out.println(“\t" + aplicacao); }

(5)

// ... Continuação

public void assar() {

System.out.println("Assando durante 25 minutos a 350º"); }

public void fatiar() {

System.out.println("Cortando a pizza em fatias diagonais"); }

public void embalar() {

System.out.println("Embalando na embalagem padrão"); }

public String getNome() { return nome; }

} // Final

public classPizzaMussarelaSaoPauloextendsPizza{ publicPizzaMussarelaSaoPaulo(){

nome= "Pizza Mussarela"; massa= "Média"; molho= "Marinara";

aplicacoes.add("Mussarela Fresca"); aplicacoes.add("Orégano"); aplicacoes.add("Parmesão");

aplicacoes.add("Azeitona verde com pimentão"); }

}

public classPizzaMussarelaRioDeJaneiroextendsPizza{ publicPizzaMussarelaRioDeJaneiro(){

nome= "Pizza Mussarela"; massa= "Fina Crocante"; molho= "Tomate"; aplicacoes.add("Mussarela"); aplicacoes.add("Orégano"); aplicacoes.add("Azeitona Preta"); } }

public classPizzariaRioDeJaneiro extendsPizzaria {

publicPizza criarPizza(String tipo) { Pizza pizza = null;

if (tipo.equals("Mussarela")) {

pizza = new PizzaMussarelaRioDeJaneiro(); } else if (tipo.equals("Calabresa")) {

pizza = new PizzaCalabresaRioDeJaneiro(); } else if (tipo.equals("Portuguesa")) {

pizza = new PizzaPortuguesaRioDeJaneiro(); } else if (tipo.equals("Napolitana")) {

pizza = new PizzaNapolitanaRioDeJaneiro(); } else if (tipo.equals("Marguerita")) {

pizza = new PizzaMargueritaRioDeJaneiro(); }

return pizza; }

}

public class PizzariaSaoPauloextends Pizzaria {

public Pizza criarPizza(String tipo) { Pizza pizza = null;

if (tipo.equals("Mussarela")) {

pizza = new PizzaMussarelaSaoPaulo(); } else if (tipo.equals("Calabresa")) {

pizza = new PizzaCalabresaSaoPaulo(); } else if (tipo.equals("Portuguesa")) {

pizza = new PizzaPortuguesaSaoPaulo(); } else if (tipo.equals("Napolitana")) {

pizza = new PizzaNapolitanaSaoPaulo(); } else if (tipo.equals("Marguerita")) {

pizza = new PizzaMargueritaSaoPaulo(); }

return pizza; }

}

public classTestaPizzaria {

public static voidmain(String[] args) {

Pizzaria pizzariaSaoPaulo = newPizzariaSaoPaulo(); Pizzaria pizzariaRioDeJaneiro = newPizzariaRioDeJaneiro(); System.out.println("José pediu uma Pizza Mussarela em São Paulo"); Pizza pizza= pizzariaSaoPaulo.pedirPizza("Mussarela");

System.out.println("José recebeu uma "+ pizza.getNome() + ".\n"); System.out.println("Dirceu pediu uma Pizza Mussarela no Rio de

Janeiro"); pizza = pizzariaRioDeJaneiro.pedirPizza("Mussarela");

System.out.println("Dirceu recebeu uma "+ pizza.getNome() + ".\n"); }

(6)

José pediu uma Pizza Mussarela em São Paulo

Preparando Pizza Mussarela

Preparando a massa: Média

Adicionando molho: Marinara

Adicionando aplicações:

Mussarela Fresca

Orégano

Parmesão

Azeitona verde com pimentão

Assando durante 25 minutos a 350º

Cortando a pizza em fatias diagonais

Embalando na embalagem padrão.

José recebeu uma Pizza Mussarela.

Saída do Programa

Dirceu pediu uma Pizza Mussarela no Rio de Janeiro

Preparando Pizza Mussarela

Preparando a massa: Fina Crocante

Adicionando molho: Tomate

Adicionando aplicações:

Mussarela

Orégano

Azeitona Preta

Assando durante 25 minutos a 350º

Cortando a pizza em fatias diagonais

Embalando na embalagem padrão.

Dirceu recebeu uma Pizza Mussarela.

Saída do Programa

Factory Method

Intenção

Definir uma interface para criar um objeto,

mas deixar as subclasses decidirem que

classe instanciar. O Factory Method permite

adiar a instanciação para subclasses. [GoF]

Também conhecido como

Virtual Constructor. [GoF]

Factory Method

Aplicabilidade [GoF]

Use o padrão Factory Method quando:

• Uma classe (o criador) não pode antecipar a

classe de objetos que deve criar;

• Uma classe quer que suas subclasses

especifiquem os objetos que criam;

• Classes delegam responsabilidade para

uma entre várias subclasses de apoio e

queremos localizar num ponto único o

conhecimento de qual subclasse está sendo

usada.

Factory Method

Estrutura Genérica

No exemplo visto quem seria Criador,

No exemplo visto quem seria Criador,

CriadorConcreto, Produto e ProdutoConcreto?

Criador:

Pizzaria;

CriadorConcreto:

PizzariaSaoPaulo e PizzariaRioDeJaneiro;

Produto:

Pizza;

ProdutoConcreto:

PizzaMussarelaSaoPaulo,

PizzaMussarelaRioDeJaneiro, etc.

(7)

Participantes

http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/factory.htm

Produto

: define a interface dos objetos criados pelo Factory Method;

ProdutoConcreto

: implementa a interface Produto;

Criador

: declara o Factory Method que retorna um objeto do tipo Produto;

• Às vezes, o Criador não é apenas uma interface mas pode envolver uma classe concreta que tenha uma implementação default para o Factory Method para retornar um objeto com algum tipo ProdutoConcreto default;

• Pode chamar o Factory Method para criar um produto do tipo Produto (método fábrica parametrizado);

Participantes

(Continuação)

CriadorConcreto

: faz override do Factory Method para retornar uma instância de ProdutoConcreto

Colaborações

Criador depende de suas subclasses para definir o Factory Method para que ele retorne uma instância do ProdutoConcreto apropriado

Consequências do uso do padrão Factory Method

http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/factory.htm

Factory Methods eliminam a necessidade de colocar classes específicas da aplicação no código:

• O código só lida com a interface Produto ;

• O código pode portanto funcionar com qualquer classe ProdutoConcreto;

Provê ganchos para subclasses:

• Criar objetos dentro de uma classe com um Factory Method é sempre mais flexível do que criar objetos diretamente

• O Factory Method provê um gancho para que subclasses forneçam uma versão estendida de um objeto

Considerações de implementação

http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/factory.htm

É boa prática usar uma convenção de nomes para alertar para o fato de que se está usando Factory Methods.

Exemplo: makeAbc(), makeXyz() Exemplo: criaAbc(), criaXyz()

Padrões relacionados [GoF]

Abstract Factory é freqüentemente

implementado utilizando o padrão Factory

Method.

Factory Methods são usualmente chamados

dentro de Template Methods.

Bibliografia

– GAMMA, E., HELM, R., JOHNSON, R. e VLISSIDES, J. Padrões de Projeto – Soluções reutilizáveis de software orientado a obetos. Bookman. 1995; – FREEMAN, Eric, FREEMAN, Elizabeth. Use a Cabeça!

– Padrões de Projeto, Alta Books. 2005;

– LARMAN, Craig. Utilizando UML e Padrões. 2. ed. Bookman. 2002;

http://www.dsc.ufcg.edu.br/~jacques/cursos/map/html/pat/fact ory.htm;

Referências

Documentos relacionados

thread corrente em estado de espera até que outra thread chame os métodos notify ou notifyAll liberando o

Sendo assim, a automação residencial pode prover meios para controlar todos os sistemas da residência como sistema de ar condicionado e aquecimento, home- office, contemplando

Antes de mostrarmos a rela¸ c˜ ao entre regularidade de uma curva e existˆ encia de reparametriza¸c˜ oes por comprimento de arco dessa curva, notemos uma propriedade sim- ples

A partir das análises realizadas no que tange às articulações entre processo formativo que enfatizou a ressignificação e aplicação, inferimos que a aplicação da SEA replanejada no

É o nome usado para descrever empresas que prestam serviços financeiros, tendo na tecnologia seu grande diferencial — muitas delas, inclusive, não têm agências para atender

Desta forma, além de retardar a oxidação lipídica, o preparado desenvolvido apresentou benefícios como estabilização da cor e manutenção das características sensoriais

[r]

❏ O produto e não haja informações na literatura científica, ou esta indique a necessidade da quantificação do fármaco inalterado e do metabólito, o protocolo de estudo poderá