C# - Usando Factory Pattern sem switch/if
Hoje veremos como usar o padrão Factory evitando o uso de instruções switch ou if. |
Se você procurar por exemplos usando o padrão Factory, na grande maioria, vai encontrar a implementação da Factory usando as instruções switch ou if/else.
Para mostrar um exemplo dessa implementação vejamos um cenário muito comum onde temos uma classe abstrata Cargo que define um método abstrato Nome:
abstract class Cargo { public abstract string Nome { get; } } |
A seguir temos as classes Gerente, Administrador e Programador que herdam de Cargo e sobrescrevem o método Nome:
class Gerente : Cargo { public override string Nome { get { return "Gerente"; } } } class Administrador : Cargo class Programador : Cargo
|
A seguir temos uma classe Factory com um método estático Get que retorna um tipo Cargo :
static class Factory { public static Cargo Get(int id) { switch (id) { case 0: return new Gerente(); case 1: return new Administrador(); case 2: return new Programador(); default: return new Programador(); } } } |
Como exemplo de utilização podemos definir um laço for e invocar o método Get() da Factory:
for (int i = 0; i <= 2; i++) { var cargo = Factory.Get(i); WriteLine("Quando id = {0}, cargo = {1} ", i, cargo.Nome); } ReadLine(); |
Temos aqui um exemplo de uso do Factory Method que usa métodos de fábrica para criar objetos sem ter que especificar a classe do objeto que será criado. (Este método não faz parte do livro Gof)
Nosso problema é eliminar o uso do bloco switch na classe Factory.
Naturalmente não existe apenas uma solução para fazer isso, e aqui, eu vou mostrar uma delas.
Usando um factory sem instruções switch ou if
Vamos iniciar definindo a interface ICargo
public
interface ICargo { string Nome { get; } } |
A seguir as classes Gerente, Administrador e Programador implementam esta interface:
class Gerente : ICargo { public string Nome { get { return "Gerente"; } } } class Administrador : ICargo class Programador : ICargo |
E agora temos a implementação da classe CargoFactory onde agora não estamos usando o bloco switch:
static class CargoFactory { public static T Create<T>() where T : ICargo, new() { return new T(); } } |
Nesta classe temos o método estático Create<T> onde temos uma restrição ao parâmetro genérico T que deve ser a interface ICargo e deve ter um construtor padrão sem parâmetro público.
Isso significa que T não pode ser int, float, double, DateTime ou qualquer outra estrutura (um tipo de valor), tem que ser do tipo ICargo e tem que ter um construtor padrão ou sem parâmetros.
Agora para usar a Factory podemos fazer:
using System;
ICargo cargo1 = CargoFactory.Create<Gerente>(); ICargo cargo2 = CargoFactory.Create<Administrador>(); ICargo cargo3 = CargoFactory.Create<Programador>(); Console.ReadLine(); |
Para este exemplo temos outra alternativa para o Factory que é criar uma instância da Interface usando o tipo anônimo:
static class CargoFactory { public static ICargo Create(string nomeCargo) { Type type = Type.GetType(nomeCargo); return (ICargo)Activator.CreateInstance(type); } } |
Para usar esta Factory podemos fazer assim:
ICargo cargo4 = CargoFactory.Create("Gerente"); Console.WriteLine(cargo4.Nome); |
E estamos conversados...
Pegue o projeto aqui: Factory_SemIfs.zip
"Confessai as
vossas culpas uns aos outros, e orai uns pelos outros, para que sareis. A oração
feita por um justo pode muito em seus efeitos."
Tiago 5:16
Referências:
C# - Obtendo a data e a hora por TimeZone
C# - O Struct Guid - Macoratti.net
C# - Checando Null de uma forma mais elegante
DateTime - Macoratti.net
Null o que é isso ? - Macoratti.net
Formatação de data e hora para uma cultura ...
C# - Calculando a diferença entre duas datas
NET - Padrão de Projeto - Null Object Pattern
C# - Fundamentos : Definindo DateTime como Null ...
C# - Os tipos Nullable (Tipos Anuláveis) -