Factory

Factory

Factory (Fábrica) é um padrão de projeto que visa a encapsular a criação de um objeto de certa classe. [1].

Factory é provavelmente um dos padrões que mais influencia a escrita de programas orientados a objetos que se utilizam do Princípio da Inversão de Controle quando chega a hora de instanciar objetos.

O Problema

Você precisa criar um objeto mas não quer usar a diretiva new diretamente.

A Solução

Algumas razões existem para que queria utilizar new diretamente. A primeira, e mais óbvia, é não saber que classe de objeto instanciar. Isso é comum numa aplicação bem desenhada onde variáveis são estruturadas com base em interfaces. Assim, vários tipos de objetos diferentes podem ser associadas a essa variável. Porque várias opções existem para o tipo de objeto que será atribuído à variável é útil delegar a escolha para um outro objeto: a fábrica.

Uma outra razão é a necessidade de inicializar o objeto instanciado antes de ser atribuído à variável. Importante notar que esta inicialização não depende do ambiente onde o objeto será utilizado, mas apenas da estrutura do próprio objeto. Quando o ambiente em que o objeto será usado necessita configurar o objeto sem saber qual ele é realmente o padrão Builder é utilizado. O padrão Builder prepara a construção e inicialização do objeto antes de o devolver. O padrão Factory tem total autonomia para fazer essas operações sem intervenção de mais ninguém.

Implementação

A implementação de Factory pode ser tão simples quanto fazer new dentro de um método (uma versão especial de Factory Method) ou tão complexa quanto consulta um repositório remoto por configurações de inicialização e execução da mesma. Os pontos necessários para que um objeto seja considerado uma fábrica:

  • Interface de Criação – A interface do objeto fabrica é especificada à parte. Normalmente numa classe abstrata ou numa interface
  • Encapsulamento da instanciação do objeto- As implementações da fábrica tem a responsabilidade de criar o objeto alvo.

A implementação mais simples seria:

01
02 public class AbstractProductFactory {
03
04 public abstract Product create () ;
05 }
06
07 public class SimpleProductFactoryImplo extends AbstractProductFactory {
08
09 public Factory (){}
10
11 public Product create (){
12 return new SimpleProductImpl () ;
13 }
14 }

Código 1:

Em geral a fábrica tem uma assinatura de retorno de uma interface e não de uma classe, mas é possível que tenha na assinatura uma classe também.

É importante notar que o método que cria o objeto é de instância. Ou seja, é preciso instanciar a classe de Factory para invocar o método. Caso contrário estaríamos na presença de Factory Method ou Service Locator. O objetivo de ter um objeto – e não um método – para instanciar outro objeto é promover polimorfismo da própria fábrica. Ou seja, a fabrica, ela mesma, por ser instanciada por outra fábrica ou podem existir várias implementações conforme o caso.

Fábricas e os Princípios Básicos

Factory é o padrão que melhor traduz o principio básico de programação orientada a objetos: Princípio de Separação de Responsabilidade.

Ao remover da classe que usa o objeto a responsabilidade de o inicializar tornamos essa classe menos acoplada ao resto do sistema. A classe pode agora usar o objeto sem se preocupar com criá-lo e inicializá-lo. Por outro lado, como o objeto vai ser criado apenas em um único lugar ele não precisa prover muitas formas de inicialização, diminuindo a responsabilidade de tentar saber como as outras classes vão trabalhar com ele.

Em outras palavras: usar Factory torna seu código menos acoplado e portanto mais flexível a mudanças.

Com o advento de sistemas complexos e o uso de padrões como Factory e seu primo Service Locator ficou claro que o acoplamento ainda se mantinha. É verdade que encapsulamos a instanciação do objeto que nos interessa mas temos agora que instanciar a fábrica. Ou, se não sabemos qual é, temos que instanciar a fábrica da fábrica…

A única forma de resolver este problema é não obrigar a classe que usa o objeto a saber como objeto esse objeto. Simplesmente se permite que a variável seja preenchida do exterior (um método modificador). Desta forma, o ambiente onde a classe está sendo usada por decidir qual o objeto correto que ela tem que usar e ela simplesmente o usará.Esta forma especial de separação de responsabilidade (SoC) é chamada de: Principio da Inversão do Controle (IoC). Texto em inglês também o chamam de Principio Hollywood em alusão à frase que traduz o principio : “Não ligue para nós, nós ligaremos para você” (Don’t call us, we’ll call you)

Aplicando o IoC para resolução do problema especifico de descobrir qual instância usar chegamos no conceito de Injeção de Dependência (DI). A idéia é simples. De alguma forma você declara qual objeto será usado por uma classe em particular. O sistema especial – chamado ambiente de injeção ou injection container em inglês – irá ler essa informação, inicializar o objeto certo e anexá-lo ao objeto que o irá usar. Esta técnica remove o uso de Factory no seu código, mas introduz o uso de um novo mecanismo. Frameworks como o Spring[2] e o Guice[3] fornecem estas capacidades.

Você eliminou o problema de instancializar suas classes Factory no seu código, mas não deixou de necessitar delas. O ambiente de injeção apenas transporta a responsabilidade da inicialização para fora do seu código, contudo ele não elimina essa necessidade. Afinal, os objetos têm que ser criados.

Mesmo com o uso de ambientes de injeção pode ser necessário criar fábricas especificas para instanciar seus objetos. O que o ambiente pode fazer por si é liberá-lo de fazer isso no casos simples em que a fabrica se limitaria a invocar new.

Enfim, a única forma de encapsular a instancialização de objetos é usando o padrão Factory, mesmo quando você utilizar um ambiente de injeção.

Padrões Relacionados

O padrão Factory nasce da aplicação de polimorfismo ao padrão Factory Method e é comum estar relacionado a quase todos os outros padrões de projeto já que em muitos casos é necessário encapsular a criação de algum objeto.

O padrão Factory está também associado a uma filosofia de programação orientada pelo uso de Injeção de Dependência, já que o ambiente de injeção é formalmente implementado como um Factory. A diferença é que ele produzirá qualquer tipo de objeto em particular produzirá outros Factory e/ou utilizará Factory para criar outros objetos.

Um outro padrão extremamente relacionado a Factory é o padrão Service Locator. Embora possamos pensar em Service Locator como uma especialização de Factory Method existe a necessidade de passar parâmetros para o objeto para que ele faça a sua função. Em particular podemos ter diferentes implementações que procuram os objetos de forma diferente.

Referências

[1] Design Patterns: Elements of Reusable Object-Oriented Software
Erich Gamma, Richard Helm, Ralph Johnson, John M. Vlissides
URL: 1995 Addison-Wesley
[2] Spring Framework

URL: http://www.springframework.org/
[3] Google Guice

URL: http://code.google.com/p/google-guice/

Licença

Creative Commons License Sérgio Taborda
Este trabalho é licenciado sob a
Licença Creative Commons Atribuição-Uso Não-Comercial-Não a obras derivadas 3.0 Genérica .

Deixe um comentário