Submarino.com.br

Factory Method

Objetivo

Encapsular a criação de um objeto em um método.

Propósito

Factory Method(Método de Fábrica[ção]) é um padrão de projeto que visa encapsular a criação de um objeto em um método [1]. Factory Method é provavelmente um dos padrões mais utilizados porque ele é muito natural. Ele é usado, muitas vezes, sem consciência de que está sendo usado um padrão.

Algumas razões existem para que queria encapsular a criação de um objeto em um método. A mais simples e óbvia é esconder o uso de new. A segunda, é poder escolher qual implementação realmente utilizar. Outras razões passam pelo controle de exceções o uso de técnicas de cache transparente e o acesso privilegiado ao estado de outros objetos.

Implementação

A implementação de Factory Method é, à partida, tão simples quanto fazer new dentro de um método. Não existe nenhum secreto. Por outro lado, é quando encapsulamos a construção em um método em vez de um construtor, que ganhamos a capacidade de não apenas fazer new.


	public interface Matrix {
	
		// outros método omitidos
		
		public double get(int linha, int coluna);
	
		public Matrix transpose();
	}

	public class DenseMatrix {

		// outros método omitidos
		
		
		public Matrix transpose(){
			return new MatrixTransposta(this);
		}
		
	}
	
	public class MatrixTransposta {
	
		Matrix original;
	
		public MatrixTransposta(Matrix original){
			this.original = original;
		}
		
		// outros método omitidos
		
		public Matrix transpose(){
			return original;
		}

		public double get(int linha, int coluna){
			return original.get(coluna, linha); // simplesmente trocamos a ordem.
		}
		
	
	}

Código 1:

Neste exemplo queremos obter um objeto to tipo Matrix a partir de outro objeto Matrix que represente a sua transposta. Uma matrix transposta é igual à matrix original, mas trocando os índices das linhas pelos das colunas e vice-versa. A matrix transposta da matrix transposta é a matrix original. O código acima utiliza o padrão Factory Method no método transpose em DenseMatrix criando um outro objeto que implementa a interface Matrix e que compartilha o estado do objeto corrente. O código utiliza novamente o padrão Factory Method no método transpose de MatrixTransposta em que o objeto original é retornado. Repare que aqui nenhum objeto foi realmente criado porque se usou um objeto a que já se tinha acesso.

Discussão

Note-se que o método de fábrica não é estático. Esta é uma diferença sutil mas importante entre o padrão Factory Method e Static Factory Method.

O uso de métodos permite que o objeto seja criado conforme o estado do objeto criador. Este conceito é especialmente útil quando o objeto criado é um objeto "ajudante" cujo estado é na realidade apoiado pelo estado do objeto criador. O exemplo clássico desta relação é na criação de iteradores. Embora o objeto retornado siga o padrão Iterator o iterador irá percorrer objetos em uma sequência que faz parte do estado do objeto criador.

É fácil confundir os padrões Factory Method, Factory e Static Factory Method já que embora o propósito seja o mesmo : criar um objeto, as implicações de cada um não são as mesmas.

Static Factory Method é usado como um substituto do uso de construtores e normalmente usado pela mesma classe que será retornada pelo método. O exemplo clássico seria o método getCalendar da classe Calendar ou valueOf da classe Integer.

Factory é usado como um encapsulamento da decisão da criação do objeto quando a decisão e/ou o objeto criado podem mudar no tempo ou conforme algum outro estado ou circunstância. Não se trata apenas de substituir o construtor, mas poder definir diferentes estratégias de criação do objeto.

Factory Method é usado por um objeto cuja responsabilidade principal não é criar objetos , mas sim manter algum estado ou prover algum algoritmo. O polimorfismo é possível, mas apenas se o objeto criador também for extendido de alguma forma. Ao contrário do objeto de fábrica de Factory o objeto que contém um Factory Method não existe para criar o objeto, mas ao contrário. O objeto criado é criado para ajudar o objeto criador a prover a sua funcionalidade.

Exemplos na API padrão

O principal exemplo na API padrão de Factory Method é o método iterator() na interface Collection. Este método cria e retorna um objeto iterador seguindo o padrão Iterator.

Um outro exemplo do uso de Factory Method é o método matcher(CharSequence) da classe Pattern que retorna um objeto Matcher. Aqui o objeto Matcher irá utiliza a expressão regular definida pelo objeto Pattern para analisar a sequência de caracteres passada como argumento. Diferentemente do método iterator() na interface Collection aqui é demonstrado como o objeto criado pode criar diferentes instância do objeto criado, inclusive com base em dados externos ao objeto criador.

A API padrão ainda conta com um uso de Factory Method através da interface Clonable que permite que qualquer objeto seja "clonado", ou seja, que um outro objeto seja criado com o estado exatamente igual ao objeto que o criou.

Padrões Relacionados

O padrão Factory Method nasce da aplicação direta do Principio do Encapsulamento e se relaciona a muitos outros padrões.

O padrão Factory contém pelo menos uma aplicação do padrão Factory Method já que um método é usado pela fábrica para criar o objeto.

O padrão Static Factory Method contém pelo menos uma aplicação do padrão Factory Method já que um método é usado para criar o objeto. Neste caso podemos pensar que Static Factory Method se trata de aplicar o padrão Factory Method onde o objeto criador é uma instância de Class e não um objeto instanciado de uma classe.

Como vimos antes o padrão Factory Method se relaciona ao padrão Iterator já que normalmente o iterador é criado com acesso ao estado do objeto sendo iterado.

Finalmente o padrão Factory Method pode ser relacionado aos padrões Builder e Prototype já que todas as implementações destes padrões contam com algum método que realmente constrói o objeto pretendido e o devolve.

Referências

[1] Design Patterns: Elements of Reusable Object-Oriented Software

Livro:Design Patterns: Elements of Reusable Object-Oriented Software

[2] Effective Java

Livro:Effective Java