C# -  Padrão Factory Method (evitando o uso de if/else)


 Neste artigo vamos continuar apresentando o padrão de projeto Factory Method.

Continuando o artigo anterior vou mostrar uma forma de evitar o uso de blocos de código if/else ou switch/case na lógica de criação dos objetos.

Vamos usar como exemplo o projeto criado no artigo anterior.



E vamos focar nossa atenção na classe LancheFactory cujo código é mostrado abaixo:

using ConsoleApp1.ConcreteProduct;
using ConsoleApp1.Creator;
namespace ConsoleApp1.ConcreteCreator
{
    public class LancheFactory : LancheFactoryMethod
    {
        public override Lanche CriarLanche(int tipo)
        {
            if (tipo == 1)
            {
                return new Bauru();
            }
            else if (tipo == 2)
            {
                return new Frango();
            }
            else if (tipo == 3)
            {
                return new MistoQuente();
            }
            else if (tipo == 4)
            {
                return new Vegetariano();
            }
            else
            {
                throw new System.ArgumentException("Lanche não encontrada");
            }
        }
    }
}

Embora a lógica de criação dos objetos relativos aos lanches concretos esteja agora encapsulada e centralizada em um único ponto do projeto, o que por si só facilita a manutenção do código, estamos usando no código um bloco if/else para decidir qual objeto criar com base no tipo selecionado.

Atualmente temos 4 lanches sendo instanciados mas imagine que você tenha 50 ou 100 lanches ?

Seguindo essa abordagem você teria que criar 50 ou 100 estruturas if/else ou swith/case o que pode ser cansativo.

Uma abordagem para resolver esse problema é usar uma classe Dictionary e armazenar no dicionário as instâncias que desejamos usar relacionando-as com os tipos de seleção que o usuário pode escolher.

Segundo esta abordagem o código da classe LancheFactory ficaria assim:

using ConsoleApp1.ConcreteProduct;
using ConsoleApp1.Creator;
using System;
using System.Collections.Generic;
namespace ConsoleApp1.ConcreteCreator
{
    public class LancheFactory : LancheFactoryMethod
    {
        public override Lanche CriarLanche(int tipo)
        {
            var factory = LancheFactories[tipo];
            return factory();
        }
        public static Dictionary<int, Func<Lanche>> LancheFactories =
                  new Dictionary<int, Func<Lanche>>
        {
                  { 1, ()=>new Bauru() },
                  { 2, ()=>new Frango() },
                  { 3, ()=>new MistoQuente()},
                  { 4, ()=>new Vegetariano() },
        };
    }
}

Vamos entender o código:

Criamos um método estático chamado LancheFactories onde usamos a classe Dictionary que representa uma coleção de chaves e valores.

No código as chaves são os tipos dos lanches, no exemplo temos o tipo 1, 2, 3 e 4 e eles estão associados com a instância do Lanche específico.

Note que estamos usando Delegate Func<T> que representa um ponteiro para um método. No exemplo ao conforme o tipo selecionado será retornado uma instância do Lanche que foi associado.

Esta é uma forma bem simples de não usar o bloco if/else uma outra forma seria usar polimorfismo ou aplicar Reflection.

Pegue o código do projeto aqui : FactoryMethod2.zip

"Louvai ao SENHOR, porque ele é bom, porque a sua benignidade dura para sempre."
Salmos 118:1

Referências:


José Carlos Macoratti