Padrões de projeto em .NET: Factory Method

 

Também conhecido como Virtual Constructor, este padrão tem por objetivo definir uma interface para criar um objeto, mas deixar as subclasses decidirem que classe instanciar. O Factory Method permite adiar a instanciação para subclasses.

 

Os frameworks usam classes abstratas para definir e manter relacionamentos entre objetos. Um framework é freqüentemente responsável também pela criação desses objetos.

 

Considere um framework para aplicações que possuem um cadastro de clientes. Duas abstrações-chave nesse framework são as classes Sistema e Cadastro. As duas classes são abstratas, e os clientes devem prover subclasses para realizar suas implementações específicas para a aplicação. Por exemplo, para criar uma aplicação para uma mecânica, definimos as classes SistemaMecanica e CadastroMecanica. A classe Sistema é responsável pela administração de Cadastros e irá criá-los conforme exigido – quando o usuário seleciona Consultar ou Novo, por exemplo, em um menu.

 

Uma vez que a subclasse Cadastro a ser instanciada é própria da aplicação específica, a classe Sistema não pode prever a subclasse de Cadastro a ser instanciada – a classe Sistema somente sabe quando um cadastro e não que tipo de Cadastro criar. Isso cria um dilema: o framework deve instanciar classes, mas ele somente tem conhecimento de classes abstratas, as quais não pode instanciar.

 

O padrão Factory Method oferece uma solução. Ele encapsula o conhecimento sobre a subclasse de Cadastro que deve ser criada e move este conhecimento para fora do framework.

 

As subclasses de Sistema redefinem uma operação abstrata CriarCadastro em Sistema para retornar a subclasse apropriada de Cadastro. Uma vez que uma subclasse de Sistema é instanciada, pode, então, instanciar Cadastros específicos da aplicação sem conhecer suas classes. Chamamos CriarCadastro um factory method porque ele é responsável pela “manufatura” de um objeto.

 

Quando usar Factory Method?

Use o padrão Factory Method quando:

 

  • Uma classe não pode antecipar a classe de objetos que criam;
  • Uma classe quer que suas subclasses especifiquem os objetos que criam;
  • As classes delegam responsabilidade para uma dentre várias subclasses auxiliares, e você quer localizar o conhecimento de qual subclasse auxiliar que é a delegada 

Estrutura

 

padprofactmethfig01.JPG

 

  • Produto (Cadastro): define a interface de objetos que o método fábrica cria.
  • ProdutoConcreto (MeuCadastro): implementa a interface de Produto.
  • Criador (Sistema): declara o método fábrica, o qual retorna um objeto do tipo Produto. Criador também pode definir uma implementação por omissão do método factory que retorna por omissão um objeto ProdutoConcreto.
  • CriadorConcreto (MeuSistema): redefine o método-fábrica para retornar a uma instância de um ProdutoConcreto.

 

Exemplo de código

Existem duas variedades principais para o padrão Factory Method. Na primeira, a classe Criador é uma classe abstrata e não fornece uma implementação para o método-fábrica que ela declara. Na segunda, Criador é uma classe concreta e fornece uma implementação por omissão para o método-fábrica. Também é possível ter uma classe abstrata que define uma implementação por omissão, mas isto é menos comum.

 

O primeiro caso exige subclasses para definir uma implementação porque não existe uma omissão razoável, assim contornando o dilema de ter que instanciar classes imprevisíveis. No segundo caso, o CriadorConcreto usa o método fábrica principalmente por razões de flexibilidade. Está seguindo uma regra que diz: “criar objetos numa operação separada de modo que subclasses possam redefinir a maneira como eles são criados”. Essa regra garante que projetistas de subclasses, caso necessário, possam mudar a classe de objetos que a classe ancestral instancia.

 

Vejamos, então, um exemplo para o segundo caso, em que o CriadorConcreto tem liberdade para definir o método-fábrica.

 

Public Interface Sistema

 

    Function Criar(ByVal CadastroID As String) As Cadastro

 

End Interface

 

Public Class SistemaMecanica

    Implements Sistema

 

 

    Public Function Criar(ByVal CadastroID As String) As Cadastro _  

    Implements Sistema.Criar

 

        If CadastroID.Trim.ToUpper.Equals("MECANICA") Then

            Return New CadastroMecanica

        ElseIf CadastroID.Trim.ToUpper.Equals("PADARIA") Then

            Return New CadastroPadaria

        End If

 

    End Function

 

End Class

 

No próximo artigo estaremos discutindo outro padrão de criação: Prototype