Design Patterns – Factory

Vamos adicionar mais um padrão para nossa caixa de ferramentas, vamos falar sobre o Factory, um padrão que fornece a possibilidade de criarmos uma fabrica para criação dos nossos objetos em tempo de execução, deixando o cliente isento de instanciar a classe ganhando um dinamismo para a aplicação

Vamos adicionar mais um padrão para nossa caixa de ferramentas, vamos falar sobre o Factory, um padrão que fornece a possibilidade de criarmos uma fabrica para criação dos nossos objetos em tempo de execução, deixando o cliente isento de instanciar a classe ganhando um dinamismo para a aplicação.

Neste artigo vamos criar uma fabrica de robôs, onde teremos três classes concretas de robôs, uma classe abstrata para os robôs e uma fabrica para instanciarmos os robôs na aplicação, todas as classes concretas deverão ser capazes de sobreviver na aplicação de forma independente da fabrica, o resultado que vamos alcançar com a criação da fabrica é podermos instanciar robôs concretos de forma dinâmica, hora instanciaremos uma classe hora outra, sem termos que alterar a tipo do objeto que esta no teste.

Quando temos um grupo de classes concretas relacionadas teríamos que escrever o código assim:

String tipo = "C6PO";

robos robo;

if (tipo.Equals("C6PO"))

robo = new C6PO();

else if (tipo.Equals("Bumblebee"))

robo = new Bumblebee();

else if (tipo.Equals("Optimus_Prime"))

robo = new Optimus_Prime();

Assim temos varias classes sendo instanciadas, e a decisão de qual instanciar é tomada no tempo de execução. Um código assim no meio da sua aplicação pode gerar problemas na hora de adicionar ou remover robôs, e esse tipo de código sempre termina espalhado no seu aplicativo, sendo assim você teria que procurar e analisar todos os locais que você utilizou esse bloco.

Vamos ver como o factory vai nos ajudar nas questões levantadas.

Vamos começar pelos enumeradores, ainda vai ficar um enumerador que iremos criar quando criarmos a fabrica.

public enum EDirecaoAndar

{

Frente,

Traz,

Esquerda,

Direita

}

 

public enum EGirar

{

Esquerda,

Direita

}

 

public enum EModo

{

veiculo,

robo

}

Os nossos robôs terão ações e modo, as ações serão Andar, Girar, Transformar e executar Scripts, e os modos são veículo e robô.

Agora criaremos a classe abstrata que será base de nossos robôs.

public abstract class robos

{

protected String nome { get; set; }

 

protected EModo Modo { get; set; }

 

public void andar(EDirecaoAndar Direcao, int passos)

{

Console.WriteLine("O robo está andando para passo(s)", this.nome, Direcao.ToString(), passos);

}

 

public void Girar(EGirar Movimento, int grau)

{

Console.WriteLine("O robo está girando para º", this.nome, Movimento.ToString(), grau);

}

 

public abstract void Transformar();

 

public abstract void Script(int Numero);

 

}

Os métodos Girar e Andar já são implementados na classe base, e os métodos Transformar e Script são abstrata para obrigar as classes que herdam a classe base implementar estes métodos, teremos em mente as seguintes situações:

O método Transformar vai alterar o modo de veículo para robô e vice e versa;

O método Script vai ser a chamada para ações em lote e/ou novas ações;

Poderíamos ter criado uma interface ao invés de uma classe abstrata, mas eu queria deixar os métodos comum a todos já implementado, assim ganhando produtividade.

Criaremos agora as classes concretas dos robôs cada um com uma característica diferente e todos herdando da classe abstrata “robos”.

public class C6PO : robos

{

public C6PO()

{

this.nome = "C6PO";

this.Modo = EModo.robo;

}

 

public override void Transformar()

{

Console.WriteLine(" não tem opção de se transformar!", this.nome);

//this.Modo = (this.Modo == EModo.veiculo ? EModo.robo : EModo.veiculo);

}

 

public override void Script(int Numero)

{

this.andar(EDirecaoAndar.Frente, 20);

this.Girar(EGirar.Esquerda, 90);

this.andar(EDirecaoAndar.Frente, 100);

this.Girar(EGirar.Direita, 19);

}

}

 

public class Optimus_Prime : robos

{

public Optimus_Prime()

{

this.nome = "Optimus_Prime";

this.Modo = EModo.veiculo;

}

 

public override void Transformar()

{

this.Modo = (this.Modo == EModo.veiculo ? EModo.robo : EModo.veiculo);

 

Console.WriteLine(" em modo ", this.nome, this.Modo.ToString());

}

 

public override void Script(int Numero)

{

switch (Numero)

{

case 1:

if (this.Modo == EModo.veiculo)

this.Transformar();

this.Girar(EGirar.Esquerda, 25);

this.andar(EDirecaoAndar.Esquerda, 2);

this.andar(EDirecaoAndar.Frente, 10);

break;

}

 

 

}

}

 

public class Bumblebee : robos

{

public Bumblebee()

{

this.nome = "Bumblebee";

this.Modo = EModo.veiculo;

}

 

public override void Transformar()

{

this.Modo = (this.Modo == EModo.veiculo ? EModo.robo : EModo.veiculo);

 

Console.WriteLine(" em modo ", this.nome, this.Modo.ToString());

}

 

public override void Script(int Numero)

{

switch (Numero)

{

case 1:

if (this.Modo == EModo.veiculo)

this.Transformar();

this.Girar(EGirar.Direita, 1);

this.andar(EDirecaoAndar.Esquerda, 2);

this.andar(EDirecaoAndar.Frente, 1);

break;

case 2:

if (this.Modo == EModo.veiculo)

this.Transformar();

this.andar(EDirecaoAndar.Frente, 15);

this.andar(EDirecaoAndar.Direita, 4);

this.Girar(EGirar.Direita, 180);

this.andar(EDirecaoAndar.Frente, 2);

break;

case 3:

if (this.Modo == EModo.veiculo)

this.Transformar();

Console.WriteLine(" fez alguns passos de samba.", this.nome);

break;

}

 

 

}

}

Criamos as três classes robôs C6PO, Optimus_Prime e Bumblebee, essas implementa os script, implementa ou não o Transformar.

Neste momento temos os robos que podem ser utilizados em nosso aplicativo perfeitamemente de forma direta e convencional, mas a nossa atenção não é essa...

Agora vamos implementar o conceito do padrão factory, bom já temos a classe abstrata robos que será fundamental para nossa fabrica, pois será o tipo retornado da nossa fabrica. Antes de ir para a fabrica vamos criar mais um enumerador para ser utilizado na factory. 

public enum ERobos

{

C6PO,

Optimus_Prime,

Bumblebee

}

Temos ai os nomes das nossas classes. Entenda que para cada classe concreta que criarmos terá que criar um item neste enumerado. Esse passo não é fundamental, mas para termos uma melhor manipulação na hora de utilizarmos os factory.

E agora vamos criar a nossa fabrica.

public static class Factory

{

public static robos Criar(ERobos robo)

{

return Criar(robo.ToString());

}

 

public static robos Criar(String robo)

{

switch (robo)

{

default:

case "C6PO":

return new C6PO();

case "Optimus_Prime":

return new Optimus_Prime();

case "Bumblebee":

return new Bumblebee();

}

}

}

A fabrica é uma classe static com os métodos statics. O método Criar tem uma sobrecarga, podemos passa o nome da classe ou uma opção do enumerador. Essa classe será responsável por instanciar as classes e retornará um objeto do tipo “robos”. Você pode estar pensando, “Esse bloco de código é muito parecido com o primeiro apresentado”, sim, é praticamente o mesmo, a diferença que agora temos uma classe responsável por isso, com isso não vamos espalhar código para decidir qual rodo será instanciado, em case de uma expansão, faremos facilmente a inserção do robô na nossa fabrica, e independentemente de onde estamos utilizando ela teremos um resultado literalmente igual.

Agora testaremos a nossa fabrica.

class teste

{

static void Main(string[] args)

{

List<ERobos> Robos = new List<ERobos> { ERobos.C6PO, ERobos.Bumblebee, ERobos.Optimus_Prime };

 

robos robo1;

 

Robos.ForEach(delegate(ERobos R)

{

robo1 = Factory.Criar(R);

robo1.Script(0);

robo1.Transformar();

robo1.Script(1);

robo1.Script(2);

robo1.Script(3);

robo1.Transformar();

Console.WriteLine();

});

 

Console.ReadKey();

}

}

A essência deste teste será, criaremos uma lista dos enumeradores com um de cada opção, temos também o robo1 do tipo robos que recebera a classe criada pelo factory, depois disso vamos fazer um for e colocar a posição da lista para criar os objetos do tipo, e com isso executar os métodos das classes fornecida pela fabrica.

Chegamos ao fim deste artigo, espero novamente ter conseguido passar a idéia desse conceito. Até a próxima, ahh não esqueçam de fazer o download do exemplo.

 

Fontes:

FREEMAN, ERIC & FREEMAN, ELISABETH – Use a Cabeça! Padrões de Projetos (Design Patterns), 2ª Edição [http://www.livrariasaraiva.com.br/produto/1995765/]

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados