O padrão AbstractFactory
23/02/2010 | Por Carlos Eduardo Ferreira | Categoria: PADRÕES DE PROJETOO padrão Abstract Factory
Abstract Factory é um padrão de criação e como o nome diz ‘Fabrica Abstrata’ este padrão é utilizado para a criação de objetos relacionados ou ‘família de objetos’.

Figura 1: Diagrama de Classes para o Abstract Factory.
Problema
Precisamos criar famílias de objetos relacionados e cada objeto de cada família tem sua implementação especifica. Você precisa garantir que dada uma situação você escolherá a família correta de objetos que será utilizado sem misturar os objetos de famílias diferentes.
Imagine que você esteja desenvolvendo uma aplicação de gerenciamento de documentos (GED) e precise tratar diferentes tipos de arquivos: txt, pdf, doc e etc.
Dentro deste contexto você terá objetos para extração e indexação de conteúdo para cada tipo de arquivo (mime-type).

Figura 2: Diagrama de Classes para o Abstract Factory do nosso exemplo.
Implementação
Observe que na classe Client utiliza somente as interfaces não as implementações.
package br.ged.abstractfactory.interfaces; public interface DocumentFactory { public static final String TXT = "TXT"; public static final String PDF = "PDF"; public DocumentReader createDocumentReader( ); public DocumentWriter createDocumentWriter( ); }
package br.ged.abstractfactory.interfaces; import java.io.OutputStream; public interface DocumentReader { public OutputStream readeFile( String file ); }
package br.ged.abstractfactory.interfaces; import java.io.InputStream; public interface DocumentWriter { public void writeFile( InputStream inputStream ); }
package br.ged.abstractfactory.concrete; import br.ged.abstractfactory.interfaces.DocumentFactory; import br.ged.abstractfactory.interfaces.DocumentReader; import br.ged.abstractfactory.interfaces.DocumentWriter; public class PdfDocumentFactory implements DocumentFactory { @Override public DocumentReader createDocumentReader( ) { System.out.println( "PdfDocumentFactory.createDocumentReader ::: PDF" ); return new PdfDocumentReader( ); } @Override public DocumentWriter createDocumentWriter( ) { System.out.println( "PdfDocumentFactory.createDocumentWriter ::: PDF" ); return new PdfDocumentWriter( ); } }
package br.ged.abstractfactory.concrete; import java.io.OutputStream; import br.ged.abstractfactory.interfaces.DocumentReader; public class PdfDocumentReader implements DocumentReader { @Override public OutputStream readeFile( String file ) { System.out.println( "PdfDocumentReader.readeFile ::: PDF" ); return null; } }
package br.ged.abstractfactory.concrete; import java.io.InputStream; import br.ged.abstractfactory.interfaces.DocumentWriter; public class PdfDocumentWriter implements DocumentWriter { @Override public void writeFile(InputStream inputStream) { System.out.println( "PdfDocumentWriter.writeFile ::: PDF" ); } }
package br.ged.abstractfactory.concrete; import br.ged.abstractfactory.interfaces.DocumentFactory; import br.ged.abstractfactory.interfaces.DocumentReader; import br.ged.abstractfactory.interfaces.DocumentWriter; public class TxtDocumentFactory implements DocumentFactory { @Override public DocumentReader createDocumentReader( ) { System.out.println( "TxtDocumentFactory.createDocumentReader ::: TXT" ); return new TxtDocumentReader( ); } @Override public DocumentWriter createDocumentWriter( ) { System.out.println( "TxtDocumentFactory.createDocumentWriter ::: TXT" ); return new TxtDocumentWriter( ); } }
package br.ged.abstractfactory.concrete; import java.io.OutputStream; import br.ged.abstractfactory.interfaces.DocumentReader; public class TxtDocumentReader implements DocumentReader { @Override public OutputStream readeFile(String file) { System.out.println( "TxtDocumentReader.readeFile ::: TXT" ); return null; } }
package br.ged.abstractfactory.concrete; import java.io.InputStream; import br.ged.abstractfactory.interfaces.DocumentWriter; public class TxtDocumentWriter implements DocumentWriter { @Override public void writeFile(InputStream inputStream) { // persiste arquivo baseado no inputstream System.out.println( "TxtDocumentWriter.writeFile ::: TXT" ); } }
package br.ged.abstractfactory.concrete; import java.io.OutputStream; import br.ged.abstractfactory.interfaces.DocumentFactory; import br.ged.abstractfactory.interfaces.DocumentReader; import br.ged.abstractfactory.interfaces.DocumentWriter; public class Client { public static void main(String[] args) throws Exception { // OBSERVE QUE USAMOS AQUI APENAS AS INTEFACES DocumentFactory documentFactory = createDocumentFactory( "PDF" ); DocumentWriter documentWriter = documentFactory.createDocumentWriter(); documentWriter.writeFile( null ); DocumentReader documentReader = documentFactory.createDocumentReader(); OutputStream outputStream = documentReader.readeFile("dados.txt"); } public static DocumentFactory createDocumentFactory( String type ) { if ( type.equalsIgnoreCase( DocumentFactory.PDF ) ) return new PdfDocumentFactory(); if( type.equalsIgnoreCase( DocumentFactory.TXT ) ) return new TxtDocumentFactory(); return null; } }
Utilizações comuns
Utilize quando quiser ter independência de como seus objetos são criados, ou seja você deseja desacoplar sua aplicação e as famílias de objetos utilizadas por ela. Dessa forma podemos trocar a família de objetos utilizadas na aplicação sem afetar o código fonte.
Utilize quando quiser fornecer uma biblioteca de classes de produtos e quer revelar somente suas interfaces e as implementações.
Conclusões
Embora utilizar o AbstractFactory gere um trabalho adicional (escrever produtos abstratos, fabricas abstratas, e suas respectivas implementações) , utilizar fabricas é uma boa prática de programação e ajuda a reduzir o acoplamento e conseqüentemente melhora manutenção do sistema.


