Static Factory Method

Objetivo

Documentar e/ou simplificar a criação de um objeto substituindo o uso do construtor por um método estático explicito.

Propósito

Quando usamos um construtor diretamente no código, perdemos a semântica do significado dos parâmetros e perdemos controle sobre a inicialização do objeto. Isso tem implicações na nomenclatura e na documentação do código porque sempre que o programador se depara com um construtor tem que consultar o javadoc para saber o significado de cada parâmetro.

Criar um, ou mais, métodos estáticos que têm nomes claros, especificam o que os parâmetros significam e encapsulam a real criação do objeto é uma forma simples de ganhar muita produtividade, diminuir acoplamento e aumentar a legibilidade [[1]]

Implementação

A implementação deste padrão é muito simples. Basta declarar o construtor privado e criar um, ou mais, métodos estáticos que realmente criam o objeto.

public class Complex {


	public static Complex real(double real){
		return complex(real,0.0);
	}

	public static Complex imaginary(double imaginary){
		return complex(0.0,imaginary);
	}

	public static Complex complex(double real, double imaginary){
		return new Complex(real,imaginary);
	}

	public static Complex polar(double amplitude, double phase){
		double real = amplitude * Math.cos(phase);
		double imaginary = amplitude * Math.sin(phase);

		return new Complex(real,imaginary);
	}

	private static Complex ONE = return new Complex(1,0);
	private static Complex ZERO = return new Complex(0,0);
	private static Complex I = return new Complex(0,1);

	public static Complex one(){
		return ONE;
	}

	public static Complex zero(){
		return ZERO;
	}

	public static Complex i(){
		return I;
	}

	private Complex(double real, double imaginary){
		this.real = real;
		this.imaginary = imaginary;
	}

	// resto dos métodos da classe

}

Para cria um número complexo são precisos dois valores. Um para parte real e outro para a parte imaginária. Contudo esses valores podem ser dados em forma geométrica ou em forma polar. Apenas usando construtores seria impossivel determinar qual a forma que o programador está usado. Além de que não é possível criar dois construtores com o mesmo numero e tipo de parâmetros, o que nos obrigaria a ter que escolher entre a forma retangular e a polar.

// atenção: este codigo não compila
public class Complex{

     public Complex(double real, double imaginary){
     	//constroi de um jeito
     	...
     }

	 public Complex(double angle, double phase){
	 	// constroi de outro
		...
	 }
}

O uso de Static Factory Method possibilita ainda poder fazer cache dos valores ou retornar valores constantes. Podemos ver esta técnica sendo usada com ONE , ZERO e I

Note ainda que os métodos de construção podem ter ou não ter parâmetros.

Discussão

O padrão Static Factory Method é, em geral, uma alternativa melhor ao uso de construtores. Permite criar os objetos sem expor a forma de criação ou carecer do uso do operador new. Podemos entender este padrão como uma forma de construtor nomeado em que podemos dar um nome ao construtor e portanto um significado aos seus comportamento e parâmetros.

Além disso permite que modifiquemos a forma de criação ou incluamos mecanismos de cache.

++ Exemplos na API padrão

Existem muitos exemplos na API padrão do uso de Static Factory Method principalmente nos objetos wrapper como Integer e BigDecimal através dos métodos valueOf. No caso de Integer existe até um mecanismo de cache de valores que auxiliar a aumentar a performance das operações de auto-boxing.

As classes Calendar e Locale também fazem uso de Static Factory Method através dos métodos getInstance.

A partir do Java 5 foi incluída a funcionalidade de Enumerações. Todas as enumarações contam com métodos valueOf() que são implementações de Static Factory Method.

Finalmente, um caso mais interessante do uso de Static Factory Method é o método valueOf da classe Boolean. Este método apenas retorna Boolean.TRUE ou Boolean.FALSE e a única coisa que ele faz é decidir qual, algo assim:

	public Boolean valueOf(boolean value){
		return value ? Boolean.TRUE : Boolean.FALSE;
	}

Este método parece que vai criar um objeto, mas na realidade não o faz. Utilizar este método em vez de new Boolean(value) preserva a JVM de ficar criando e destruindo um monte de objetos iguais melhorando a performance da aplicação e demonstra perfeitamente que o uso de Static Factory Method não está apenas vinculado ao ato de criar, mas principalmente ao ato de simular a criação. Algo que com new, não podemos fazer.

O uso de Static Factory Method nas classes wrapper na biblioteca padrão foram adicionados vários anos depois da criação original das classes. Até ha pouco tempo, isto significava que nunca poderiamos tornar os construtores privados e forçar o uso dos métodos criadores que contém otimizações de performance e cache. Recentemente, por causa do projeto Valhalla os construtores estão sendo tornados obsoletos e eventualmente serão removidos. Esta é uma decisão que afeta muitos desenvolvedores e que está sendo tomada agora de uma forma destrutiva. Este é um exemplo da razão pela que devemos sempre presar pelo encapsulamento de decisões, especialmente a decisão de instanciação e usar new diretamente o menos possível.

Padrões associados

Como o próprio nome indica Static Factory Method é uma derivação do padrão Factory Method onde o fator da herança e polimorfismo das fábricas é removido.

O padrão Static Factory Method pode ser associado a qualquer tipo de objeto, mas é normalmente mais usual vê-lo associado a objetos que também são instancias de Value Object. Isto permite realizar cache e usar o padrão Shared Object.

O padrão Singleton usa o Static Factory Method para esconder e tomar controle sobre a sua instanciação.

Bibliografia

[1] Joshua Bloch Effective Java, 2nd Edition: Fonenix inc (2008)

[2] Java Tip #2: Static factory methods vs. constructors (http://blog.codefront.net/2003/06/21/java-tip-2-static-factory-methods-vs-constructors/)

[3] Ralph Johnson, Erich Gamma, John Vlissides, Richard Helm Design Patterns: Elements of Reusable Object-Oriented Software: Addison-Wesley (2005)

Scroll to Top