O padrão Factory Method

12/04/2010 | Por Carlos Eduardo Ferreira | Categoria: PADRÕES DE PROJETO

Olá 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.

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.

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.

Tags: ,

Deixar comentário