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 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 e 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.
- O cliente é um objeto que requer uma instância de outro objeto (o produto) para algum propósito. Ao invés de criar a instância do produto diretamente, o cliente delega esta responsabilidade para a fábrica;
- Uma vez invocada, a fábrica cria uma nova instância do produto, passando-o de volta para o cliente. Simplificando, o cliente usa a fábrica para criar uma instância do produto;
- A figura abaixo mostra a relação lógica entre estes elementos do padrão:
Com o padrão Factory, temos uma maneira simples e limpa para instanciar, no momento da implementação, um objeto desconhecido. 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 eu, seja uma dos mais simples:
- 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;
- A fábrica cria uma instância de um novo produto concreto e retorna ao cliente o produto recém-criado;
- 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; }
}
A seguir, vamos criar três classes: Gerente, Analista e Programador, essa última 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";}
}
}
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();
}
}
}
No método Main(), da classe Program, vamos utilizar a fábrica 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:
- A inclusão de um novo produto (um novo cargo) fará com que a classe Factory tenha que ser alterada;
- Ocorre a violação do princípio Open/Closed (você deve ser capaz de estender um comportamento de uma entidade de software (classe), sem modificá-la).
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







