.NET - Princípios de Programação e Padrões de Projetos - II


Na primeira parte do artigo eu apresentei alguns conceitos básicos sobre os princípios SOLID e sobre os padrões de projeto.

Vamos agora partir para a parte prática e mostrar os conceitos e a implementação dos principais padrões de projeto usando a linguagem C#.

Vou iniciar com o padrão Factory.

1 - Padrão de Projeto Factory (Fábrica)

É um padrão Criacional

Definição: Define uma interface para criar um objeto, mas deixa as subclasses decidirem que classe instanciar (Gamma, pag. 104).

Obs: O método Factory permite que uma classe adie a instanciação para as subclasses.

Este padrão é usado para substituir um construtor de classe(s), permitindo que o tipo de objeto a ser instanciado seja determinado em tempo de execução, sendo usado para controlar uma instanciação de classe.

O uso deste padrão de projeto reduz o acoplamento entre classes, e oferece muito mais flexibilidade no futuro, se os requisitos de sua aplicação mudarem.

Um benefício do padrão de Factory é permitir ao cliente focar no seu papel na arquitetura, porque permite a separação da criação e instanciação de objetos a partir do cliente.

Existem inúmeras variações do padrão Factory, mas em geral sempre temos um modelo básico que envolve os mesmos atores principais, um cliente, uma fábrica, e um produto.

Com o padrão Factory temos assim uma maneira simples e limpa para instanciar um objeto desconhecido para nós no momento da implementação. A única coisa que precisamos conhecer é a interface do objeto com um conjunto de propriedades predefinidos e métodos que precisamos usar.

Implementação

Existem diversas maneiras de implementar o padrão Factory (Fábrica) a seguir temos um modelo básico de implementação que creio seja uma dos mais simples:

  1. O cliente precisa de um produto, mas em vez de criá-lo diretamente, usando o operador new, ele pede para a fábrica criar um novo produto, fornecendo as informações sobre o tipo de objeto que ele precisa;
  2. A fábrica cria uma instancia de um novo produto concreto e retorna ao cliente o produto recém-criado;
  3. O cliente usa os produtos, sem conhecer nada sobre a sua implementação concreta;

Com base neste modelo vamos criar um novo projeto usando o Visual C# 2010 Express Edition do tipo Console Application com nome PadraoFactorySimples;

Vamos criar uma classe abstrata chamada Cargo que representa o cargo do funcionário na empresa (esta classe representa o produto) e que define o método Nome();

Esta classe é uma classe abstrata e não pode ser instanciada servindo como classe base para a criação de classes concretas:

  abstract class Cargo
  {
        public abstract string Nome { get; }
  }
classe abstrata que representa o produto

A seguir vamos criar três classes : Gerente, Analista e Programador que implementa a classe abstrata Cargo sobrescrevendo o método Nome da classe Cargo retornando o nome do cargo:

 class Gerente : Cargo
 {
        public override string Nome
        {
            get{return "Gerente";}
        }
 }

 class Analista : Cargo
 {
        public override string Nome
        {
            get{return "Analista";}
        }
 }

 class Programador : Cargo
 {
      public override string Nome
       {
           get{return "Programador";}
      }
 }
Classes concretas que representam os produtos concretos.

Agora vamos criar a classe Factory que representa a fábrica e que será responsável pela criação das instâncias dos objetos das classes concretas criadas anteriormente:

   static class Factory
    {
        /// <summary>
        /// Decide qual classe instanciar
        /// </summary>
        public static Cargo Get(int id)
        {
            switch (id)
            {
                case 0:
                    return new Gerente();
                case 1:
                case 2:
                    return new Analista();
                case 3:
                default:
                    return new Programador();
            }
        }
    }
classe que representa a fábrica

No método Main() da classe Program vamos utilizar a fabrica para criar as instâncias das classes concretas conforme o objeto desejado, no caso usamos um laço for/next para invocar o método Get() da classe factory passando o id do objeto desejado:

  class Program
    {
        static void Main(string[] args)
        {
            Console.WriteLine("Implementação do padrão Factory ");
            Console.WriteLine("--------------------------------");
            for (int i = 0; i <= 3; i++)
            {
                var cargo = Factory.Get(i);
                Console.WriteLine("Quando id = {0}, cargo = {1} ", i, cargo.Nome);
            }
            Console.ReadKey();
        }
    }

Esta implementação é bem simples mas apresenta o seguinte problema:

Uma variação desta implementação para contornar o problema acima é vista na figura abaixo onde podemos criar uma fábrica abstrata e a partir dela criar tantas classes concretas quanto forem necessárias:

Vamos implementar esta variação criando uma fábrica abstrata que defina o método CriaCargos() que irá gerar as instâncias dos objetos concretos:

 abstract class Fabrica
    {
        private ArrayList cargos = new ArrayList();
        // Construtor chama a Fábrica
        public Fabrica()
        {
            this.CriaCargos();
        }
        public ArrayList Cargos
        {
            get { return cargos; }
        }
        // Fábrica
        public abstract void CriaCargos();
    }

A seguir vamos criar as fábricas concretas que implementam a fábrica abstrata e que serão responsáveis pela criação dos objetos. As fábricas concretas sobrescrevem o método CriarCargos() e retornam os objetos para o cliente:

 class Administracao : Fabrica
    {
        // Implementação da Fábrica
        public override void CriaCargos()
        {
            Cargos.Add(new Gerente());
        }
    }
    class Tecnologia : Fabrica
    {
        // Implementação da Fábrica
        public override void CriaCargos()
        {
            Cargos.Add(new Analista());
            Cargos.Add(new Programador());
        }
    }

A utilização da fábrica abstrata é feita no método Main() da classe Program() que cria as instâncias das fábricas concretas e gera os objetos desejados:

     static void Main(string[] args)
        {
            //Os construtores chamam a Fábrica
            Fabrica[] fabricantes = new Fabrica[2];
          
 fabricantes[0] = new Administracao();
            fabricantes[1] = new Tecnologia();

            Console.WriteLine("Implementação do padrão Abstract Factory ");
            Console.WriteLine("-----------------------------------------");
            foreach (Fabrica fabricante in fabricantes)
            {
                Console.WriteLine("\n" + fabricante.GetType().Name + "--");
                foreach (Cargo cargo in fabricante.Cargos)
                {
                   Console.WriteLine(" " +  cargo.GetType().Name);
                }
            }
            Console.ReadKey();
        }

Pegue o projeto completo aqui: PadraoFactorySimples.zip

Slm 131:1 Senhor, o meu coração não é soberbo, nem os meus olhos são altivos; não me ocupo de assuntos grandes e maravilhosos demais para mim.

Slm 131:2 Pelo contrário, tenho feito acalmar e sossegar a minha alma; qual criança desmamada sobre o seio de sua mãe, qual criança desmamada está a minha alma para comigo.

Slm 131:3 Espera, ó Israel, no Senhor, desde agora e para sempre.

Em artigos futuros estarei implementando outros padrões de projetos na linguagem C#. Aguarde...


José Carlos Macoratti