1. Factory Method (Método Fábrica)
1.1. Definição
📘"Fornece uma interface para criar um objeto, mas permite às subclasses decidirem qual tipo de objeto instanciar." [UCPP]
1.2. Aplicabilidade
Podemos utilizar o padrão quando:
-
uma classe precisa utilizar um tipo de objeto, mas ela não tem como decidir qual tipo concreto utilizar, pois tal lógica é definida por subclasses;
-
cada subclasse tem uma lógica diferente para a criação dos objetos (juntar estas lógicas na superclasse tornaria o código extenso e confuso);
-
novas subclasses puderem ser introduzidas a qualquer momento com diferentes lógicas;
-
você não conhece todos os tipos concretos de objetos que podem ser criados;
-
é necessário criar objetos por meio de composição, cada objeto instanciado é um todo composto por diferentes partes, tais partes devem ser escolhidas de acordo com o todo.
1.3. Modelagem
TipoAbstrato
é uma interface ou classe abstrata/super classe que representa o tipo dos objetos que a fábrica pode criar.
As classes TipoConcreto1
até TipoConcretoN
representam os tipos concretos que podem ser instanciados de fato pela fábrica.
CriadorAbstrato
representa a implementação base da fábrica. Ela pode ter quaisquer métodos que forem necessários,
incluindo um método abstrato newObject()
que deverá ser implementados pelos criadores concretos.
A classe CriadorAbstrato
normalmente terá um método que chamará o newObject()
para usar o objeto criado.
Neste exemplo, tal método é o useObject()
, mas em uma implementação real, o método deve ter um nome de acordo
com o problema sendo resolvido.
Diferente da Simple Factory:
-
a lógica que define qual objeto será instanciado não é centralizada em uma classe, mas sim nas subclasses de
CriadorAbstrato
; -
logo, o método
newObject()
é abstrato, pois as subclasses deCriadorAbstrato
é que o implementarão. -
tal método não deve ser estático se ele for usado por outros métodos da classe (como é o caso deste modelo);
Cada subclasse de CriadorAbstrato
é que definirá a lógica para a instanciação do objeto representado por TipoAbstrato
.
Para a Simple Factory não existem subclasses.
Um projeto de exemplo para o diagrama apresentado está disponível aqui. Ele deve ser alterado para incluir as mudanças necessárias para o problema específico que você estiver resolvendo com o padrão.
1.4. Princípios utilizados
1.4.1. Single-Responsitility Principle
Com o Single-Responsitility Principle (SRP), a classe CriadorAbstrato
de fato não cria os objetos, apenas define um método que as filhas devem implementar para isto.
Ela apenas usará os objetos criados. Cada subclasse terá a responsabilidade de criar tais objetos.
1.4.2. Open-Closed Principle
Com o Open/Closed Principle (OCP), separamos as partes que mudam, i.e. a lógica de criação de objetos, de dentro da classe que utiliza tais objetos. Isto torna a classe que utiliza a factory "aberta para extensão e fechada para modificação".
1.4.3. Programar para uma "interface" não uma implementação
Programar para uma "interface" não uma implementação (GoF) indica que devemos declar variáveis com tipos abstratos (TipoAbstrato
) e usar tipos concretos apenas na instanciação (SubTipo1
… SubTipoN
).
1.4.4. Dependency Inversion Principle (DIP)
Ao aplicar o Dependency Inversion Principle (DIP), a classe CriadorAbstrato
não depende de tipos concretos, mas sim de tipos abstratos (interfaces ou classes abstratas).
Ela não precisa saber quais são os tipos concretos existentes.
1.5. Remodelando o projeto Exportador Produto com a Simple Factory
Antes de implementarmos o padrão Factory Method, precisamos voltar ao projeto anterior, para fazer algumas alterações considerando um novo cenário.
Os detalhes são fornecidos no projeto exportador-problematico.
1.6. Exemplos
Podemos utilizar o Factory Method para encapsular a instanciação de colunas de uma tabela em formato específico, baseado no projeto exportador-simple-factory-reflection. Implemente o projeto seguindo a modelagem abaixo:
1.7. Detalhes de Implementação
xxxxxxxxxxxx
2. Problemas da NÃO utilização do padrão
Veja o projeto exportador-problematico (zip). Ele é uma implementação do exportador de dados sem utilizar o padrão Factory Method, seguindo a modelagem do diagrama abaixo:
3. Padrões Relacionados
Padrões que possuem similaridades ou podem ser usados em conjunto: