Codificante

Fábrica Estática ou Construtores Públicos?

Marco Ferreira
Marco Ferreira

Segundo artigo da série “25 JavaBeans Series”, hoje vamos conversar sobre um ponto relacionado ao ciclo de vida de objetos Java tratado no excelente livro Effective Java Third Edition de Joshua Bloch.

Normalmente quando criamos uma classe Java é normal que utilizemos construtores públicos, porém existe uma outra forma que é basicamente criando um método estático que retorne a instância da classe. Essa técnica é conhecida como static factory method. Mas porquê usar métodos estáticos para retornar a instância da classe?

Nomes

Ao contrário dos construtores, métodos estáticos tem nomes e o fato de terem nomes facilita na legibilidade do código tanto para quem escreve o método quanto para quem vai usar o método. Uma classe pode ter apenas um construtor com uma determinada assinatura e pra fugir dessa limitação existe a prática de se criar mais de um construtor para diferentes usos apenas mudando os parâmetros. Porém essa prática carrega consigo a complexidade de ficar lembrando qual construtor tem quais parâmetros na hora de invocar essa classe, com métodos estáticos esse problema diminui.

Economia da memória Heap na JVM

Ao contrário dos construtores, não é necessário criar um novo objeto a cada invocação e isso permite o uso de instâncias já feitas sendo assim evitando criar diversos objetos e a JVM agradece. Essa abordagem lembra um pouco dos padrões Flyweight e Singleton e também é conhecida como instance-controlled.

Retorno bem definido

Ao contrário dos construtores, pode se retornar qualquer subtipo e isso permite flexibilidade na hora de escolher o tipo de retorno. Outro ponto interessante sobre essa flexibilidade, é a possibilidade de retornar um tipo específico de objeto sem a necessidade de tornar a classe pública. Por exemplo o Java Collections Framework, ele tem 45 implementações utilitárias de suas interfaces, fornecendo coleções imutáveis e coleções sincronizadas. E a maioria das implementações são exportadas por métodos estáticos de uma classe não instanciável, a java.util.Collections.

Variação de retorno de acordo com os parâmetros de entrada

A classe do objeto retornado pode variar de acordo com os parâmetros passados. Um exemplo dessa flexibilidade é a classe EnumSet que por sua vez não possui construtores públicos, apenas fábricas estáticas. Na implementação do OpenJDK ela pode retornar a instância de uma das suas duas subclasses dependendo do tamanho do enum subjacente. Se tiver 64 ou menos elementos como são de fato a maioria dos enums, então a fábrica estática vai retornar uma instância de RegularEnumSet. Se tiver 65 elementos ou mais vai retornar uma instância de JumboEnumSet.

A classe do objeto retornado não precisa existir quando a classe que contém o método é escrita

Um outro ponto interessante dessa abordagem, é pensar que ela é base para frameworks service providers como o Java Database Connectivity API(JDBC). Um framework service provider é um sistema em que o próprio provider implementa o serviço e o sistema faz as implementações que serão disponibilizadas para os clientes, dessa forma desacoplando os clientes das implementações. Os três pontos essenciais em um framework service provider são: service interface que representa uma implementação; provider registration API que os providers usam para registrar as implementações e por fim service access API no qual os clientes usam para ter instâncias do serviço.

Mas então, só existem vantagens utilizando a fábrica estática? Nada em tecnologia é bala de prata, então vamos as limitações/desvantagens:

Classes sem construtores públicos/protegidos não podem ser subclasses

Um exemplo desse cenário, é impossível de “subclassificar” qualquer uma das implementações no Collections Framework. O que por sua vez pode se tornar algo bom, porque trás consigo um ótimo incentivo para programadores usarem composição ao invés de herança.

Dificuldade de encontrar

Esses métodos estáticos não se destacam na documentação da API da mesma forma que os contrutores, por isso pode ser um pouco complicado de entender como instanciar uma classe dessas. Hoje o Javadoc não tem algo que destaque fábricas estáticas, para contornar isso você pode seguir algumas convenções de nomenclatura e claro documentar os seus métodos. Alguns exemplos de nomenclaturas para esse tipo de método:

from: Método de conversão de tipo que usa um único parâmetro e retorna a instância correspondente, por exemplo: Date data = Date.from(instant);

of: Método de agregação que utiliza vários parâmetros e retorna uma instância desse tipo que os incorpora, por exemplo: Set<Ranking> planetas = EnumSet.of(JUPITER, SATURNO, URANO);

valueOf: Método mais detalhado do que o from e o of, por exemplo: BigInteger valorMaximo = BigInteger.valueOf(Integer.MAX_VALUE);

instance ou getInstance: Método que retorna uma instância que é descrita pelos seus parâmetros se eles existirem, por exemplo: Galaxia andromeda = Galaxia.getInstance(opcoes);

create ou newInstance: Método que garante uma nova instância a cada chamada, por exemplo: Object novoArray = Array.newInstance(classeDoObjeto, tamanhoDoArray);

getType: Semelhante ao getInstance, porém usado se a fábrica estática estiver em uma classe diferente. Type é o tipo de objeto retornado pela fábrica estática, por exemplo: FileStore fs = Files.getFileStore(caminho);

newType: Semelhante ao newInstance, porém usado se a fábrica estática estiver em uma classe diferente. Type é o tipo de objeto retornado pela fábrica estática, por exemplo: BufferedReader br = Files.newBufferedReader(caminho);

type: uma alternativa mais concisa em relação ao getType e ao newType, por exemplo: List<Estrela> supernovas = Collections.list(enumSupernovas);

Bem, vimos as vantagens e desvantagens do uso de fábricas estáticas ao invés de construtores públicos. Você já havia pensado sobre o assunto? Até a próxima =)


Mais Artigos