O padrão Factory Method
12/04/2010 | Por Carlos Eduardo Ferreira | Categoria: PADRÕES DE PROJETOOlá pessoal,
Hoje vamos ver um pouco como funciona o padrão Factory Method. Este é um padrão de Criação (Creational Pattern) e lida com o problema de criação de objetos.
Problema
Este padrão é utilizado quando você deseja criar um objeto sem especificar qual a classe vai ser utilizada. O padrão resolve isso definindo uma interface para criar um objeto, mas deixando as subclasses decidirem que classe instanciar.
Figura 1: Diagrama de Classes para o Factory Method.
Utilizando nosso exemplo anterior (veja Abstract Factory) no nosso código de uma aplicação GED poderíamos utilizar o padrão Factory Method junto com o Abstract Factory. Com o Abstract Factory nos criamos as familias de objetos relacionados e com o Factory Method nos criamos a fabrica que realmente vai instanciar o classe. Ou seja, nós delegamos a factory a responsabilidade de escolher que classe instanciar.
Figura 2: Diagrama de Classes para o Factory Method do exemplo.
Implementação
Observe que modificamos as factorys do Abstract Factory (compare com o post sobre Factory Method) para agora chamar a respectiva Factory Method. Classes modificadas:
PdfDocumentFactory, TxtDocumentFactory.
package br.ged.abstractfactory.concrete; import br.ged.abstractfactory.interfaces.DocumentFactory; import br.ged.abstractfactory.interfaces.DocumentReader; import br.ged.abstractfactory.interfaces.DocumentWriter; import br.ged.factorymethod.DocumentReaderFactory; import br.ged.factorymethod.DocumentWriterFactory; public class PdfDocumentFactory implements DocumentFactory { @Override public DocumentReader createDocumentReader( ) { System.out.println( "PdfDocumentFactory.createDocumentReader ::: PDF" ); // AQUI ESTA A NOSSA FACTORY METHOD return DocumentReaderFactory.getReader( DocumentFactory.PDF ); } @Override public DocumentWriter createDocumentWriter( ) { System.out.println( "PdfDocumentFactory.createDocumentWriter ::: PDF" ); // AQUI ESTA A NOSSA FACTORY METHOD return DocumentWriterFactory.getWriter( DocumentFactory.PDF ); } }
package br.ged.abstractfactory.concrete; import br.ged.abstractfactory.interfaces.DocumentFactory; import br.ged.abstractfactory.interfaces.DocumentReader; import br.ged.abstractfactory.interfaces.DocumentWriter; import br.ged.factorymethod.DocumentReaderFactory; import br.ged.factorymethod.DocumentWriterFactory; public class TxtDocumentFactory implements DocumentFactory { @Override public DocumentReader createDocumentReader( ) { System.out.println( "TxtDocumentFactory.createDocumentReader ::: TXT" ); // AQUI ESTA A NOSSA FACTORY METHOD return DocumentReaderFactory.getReader( DocumentFactory.TXT ); } @Override public DocumentWriter createDocumentWriter( ) { System.out.println( "TxtDocumentFactory.createDocumentWriter ::: TXT" ); // AQUI ESTA A NOSSA FACTORY METHOD return DocumentWriterFactory.getWriter( DocumentFactory.TXT ); } }
package br.ged.factorymethod; import br.ged.abstractfactory.interfaces.DocumentReader; public abstract class ReaderFactory { public static DocumentReader getReader( String readerType ){ return null; } }
package br.ged.factorymethod; import br.ged.abstractfactory.interfaces.DocumentWriter; public abstract class WriterFactory { public static DocumentWriter getWriter( String readerType ){ return null; } }
package br.ged.factorymethod; import br.ged.abstractfactory.concrete.PdfDocumentReader; import br.ged.abstractfactory.concrete.TxtDocumentReader; import br.ged.abstractfactory.interfaces.DocumentFactory; import br.ged.abstractfactory.interfaces.DocumentReader; public class DocumentReaderFactory extends ReaderFactory { public static DocumentReader getReader( String readerType ) { if ( readerType != null && readerType.equalsIgnoreCase( DocumentFactory.TXT ) ) { return new TxtDocumentReader( ); } else if ( readerType != null && readerType.equalsIgnoreCase( DocumentFactory.PDF ) ) { return new PdfDocumentReader( ); } return null; } }
package br.ged.factorymethod; import br.ged.abstractfactory.concrete.PdfDocumentWriter; import br.ged.abstractfactory.concrete.TxtDocumentWriter; import br.ged.abstractfactory.interfaces.DocumentFactory; import br.ged.abstractfactory.interfaces.DocumentWriter; public class DocumentWriterFactory extends WriterFactory { public static DocumentWriter getWriter( String readerType ) { if ( readerType != null && readerType.equalsIgnoreCase( DocumentFactory.TXT ) ) { return new TxtDocumentWriter( ); } else if ( readerType != null && readerType.equalsIgnoreCase( DocumentFactory.PDF ) ) { return new PdfDocumentWriter( ); } return null; } }
Utilizações comuns
Utilize quando quiser postergar a instanciação de suas classes.
Uma classe quer que suas subclasses especifiquem os objetos que criam.
Quando a escolha de qual classe instanciar for tomada em tempo de execução.
Conseqüências
Segundo GoF o padrão Abstract Factory tem as seguintes vantagens e desvantagens:
- elimina a necessidade de anexar classes especificas das aplicações no código
- fornece um gancho para as subclasses. A criação de classes e subclasses se torna mais
flexível.
- como desvantagem podemos citar o fato de que podemos ter que criar varias subclasses da classe Creator apenas para criar um ConcreteProduct.
Conclusões
O padrão Factory Method é um velho conhecido dos programadores Java. Ele esta presente em Collections. Em Collections o método iterator é uma Factory Method. Pense aqui: ele cria um objeto, retorna uma interface, é implementado por várias classes. Este padrão é justamente sobre isso: diversas classes que implementam a mesma operação, retornam as mesma interface (ou classe abstrata) mas retornam diferentes implementações.
Por hoje é só pessoal.


