| Últimas 20 atualizações de Caio Humberto |
|
|

Muitos programadores já assinaram uma interface para criar alguma
classe para uma especifica função, já existe no próprio namespace System
algumas intefaces, por exemplo: System.IAppDomainSetup, System.IAsyncResult e
System.IServiceProvider, você pode ter visto a utilização delas em algum
exemplo ou mesmo utilizado.
Mas a questão é bem simples... Você sabe descrever o que é uma interface e/ou quais são suas utilidades e importâncias que ela tem na vida de um sistema, tanto a curto como em longo prazo?
Muito bem, se não sabe este artigo vai de ajudar e esse já sabe vale a pena conferir, pois sempre temo algo a aprender.
Primeiro vamos à definição: Interface pode conter apenas assinaturas de eventos, métodos, propriedades e indexadores.
Segundo, interfaces são contratos, a única regra que o contratante tem que seguir é implementar todos os membros da interface de forma a seguir as assinaturas dos mesmos.
Isso quer disser que: Se uma classe contrata (implementa) a interface System.IAsyncResult essa classe fica obrigada a implementar as quatro propriedades que há nesta interface.
Vamos ao exemplo:
namespace System
{
public interface IAsyncResult
{
object AsyncState { get; }
System.Threading.WaitHandle AsyncWaitHandle { get; }
bool CompletedSynchronously { get; }
bool IsCompleted { get; }
}
}
Esse é o código da interface, onde tem a assinatura de quatro propriedades, e essas propriedades deve ter obrigatoriamente o método get. OBS: Não precisa criar este bloco, eu apenas colei aqui para ficar mais fácil de observar a interface.
class AsyncResultExeplo : System.IAsyncResult
{
#region IAsyncResult Members
private object _AsyncState;
public object AsyncState
{
get { return _AsyncState; }
}
private System.Threading.WaitHandle _AsyncWaitHandle;
public System.Threading.WaitHandle AsyncWaitHandle
{
get { return _AsyncWaitHandle; }
}
private bool _CompletedSynchronously;
public bool CompletedSynchronously
{
get { return _CompletedSynchronously; }
}
private bool _IsCompleted;
public bool IsCompleted
{
get { return _IsCompleted; }
}
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

Um recurso disponibilizado a partir do C# 3.0 pode estender funcionalidades de uma classe especifica do framework.
O mais comum quando precisamos criar métodos úteis é criando classes static “helper”, “util” ou algo parecido, digamos que você passou um bom tempo criando classes e métodos que facilita o seu dia-a-dia em um projeto, digamos também que você criou tudo isso em um projeto separado e compilou em um DLL (para poder utilizar nos próximos projetos). Acontece que você fica um tempo sem precisar de um método e quando vai utilizá-lo você esquece dos namespaces, o nome dos métodos, vamos multiplicar isso para uma equipe com vários desenvolvedores que também vai esquecer os namespaces (pois já temos que lembrar de vários).
Bom, podemos criar Extension Methods e colocar esses métodos uteis junto com os métodos já existentes na classe.
Vamos criar um projeto do tipo console application eu estou utilizando o visual Studio 2010 mas, você poderá utilizar o visual Studio 2008 lembrando que o framework .net deve ser igual ou superior ao 3.0.
O que vamos fazer primeiro é criar uma classe static para os métodos uteis comuns, ou seja, da forma que estamos acostumados a criar e utilizar.
public static class comumUtil
{
public static String FormataCapitalize(string Str)
{
Str = Str.ToLower();
System.Globalization.CultureInfo cultureinfo = System.Threading.Thread.CurrentThread.CurrentCulture;
return cultureinfo.TextInfo.ToTitleCase(Str);
}
}
Como podemos ver um método que recebe uma string e transforma a primeira letra de todas as palavras e maiúscula e o restante e minúscula e retorna uma string com o resultado dessa transformação, não vamos entrar em detalhes o seu funcionamento.
A utilização do método FormataCapitalize obriga conhecer o nome completo da classe incluindo manespaces, vamos ver logo abaixo.
Console.WriteLine(comumUtil.FormataCapitalize("tESTE cOM metodo comum"));
Observem que, teremos que escrever o nome da classe “ponto” o método e passar como parâmetro uma string.
Seria muito mais intuitivo e pratico se quando estivermos em um objeto do tipo string colocássemos um “ponto” e o nosso método estivesse lá, bem no meio dos métodos já compilados na classe em questão.
E é isso que vamos fazer agora, não é complicado nem mesmo requer muitas alterações no que já temos, pode levar alguns minutos para você familiarizar.
Bom o que precisamos e é uma regra, é colocarmos o um “this” na frente do tipo do primeiro parâmetro e é esse tipo que indica qual classe será estendida, então vamos conferir como fica o nosso método estendido.
public static class ExtensionUtil
{
public static String FormataCapitalize(this string Str)
{
Str = Str.ToLower();
System.Globalization.CultureInfo cultureinfo = System.Threading.Thread.CurrentThread.CurrentCulture;
return cultureinfo.TextInfo.ToTitleCase(Str);
}
}
Agora podemos utilizar esse método de forma pratica e intuitiva.
Console.WriteLine("tESTE cOM metodo extension".FormataCapitalize());
Isso não é realmente pratico e intuitivo?
Digamos que, temos que além do parâmetro “this” também precisássemos passar outros parâmetros. Isso também é simples, pois como eu disse a única diferença é o “this” o restante é igual a métodos estáticos comum.
Vamos ver outro exemplo de extension methods.
public static String FormataMoeda(this Double valor, String formato, IFormatProvider FormatProvider)
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

Vamos continuar vendo ER, esse já é o terceiro artigo meu falando sobre essa poderosa arma. Nos outros dois artigos vimos o que são ERs e para que servem e também vimos como criar validadores (exemplo que montamos foi para validar data), mas agora vamos subir um pouco de nível vamos reconhecer capturar e modificar parte de um texto.
Novamente a linguagem será C# estou atualmente utilizando o framework 4.0, neste exemplo vou criar em “Console application”, mas vou demonstrar uma técnica para ser utilizado em aplicações Web.
Quem nunca passou por algo parecido? Você está na sua mesa numa sexta-feira por volta das 5h, contando os minutos para sair terminar o expediente quando o telefone toca e é um usuário com uma voz “doce” perguntando se não tem como ele colocar links quando publicar um produto e for escrever a descrição.
Você tem duas saídas. Fala para ele pesquisar no Google sobre a tag “a” ou cria uma forma mais simples para essa entrada.
Já digo que a primeira é furada, pois se você é uma pessoa preocupada com segurança você esta escapando todas as aspas-duplas e aspas-simples e qualquer caractere que possa vir dar problemas e isso não ira permitir que ‘<a "http://link.com.br">clique aqui</a>’ renderize de forma correta quando exibido o produto.
Agora sobrou somente uma opção. Criar uma forma de ele colocar no meio da descrição os tais links.
Então vamos pensar uma forma simples para o cliente imputar essa informação, não, já pensaram por nos, por exemplo, alguns sites de relacionamento nos permitem escrever algo do tipo [link=www.blablabla.com.br]link[/link] e será assim que vamos permitir o usuário informar os links, por dois motivos simples, primeiro que ele já deve ter utilizado isso nos sites de relacionamentos e segundo é fácil e intuitivo para ele e não vamos obrigar ele a aprender HTML.
Mãos à obra, pois vamos escrever um monte de código para fazermos esse reconhecimento. Brincadeira vai ser moleza, vamos criar uma ER mágica que vai nos ajudar em quase 90% do problema, você esta duvidando então continua lendo este artigo.
Criaremos primeiro a ER, sabemos que teremos que reconhecer no meio de um texto as ocorrências dos links que estarão todos muito parecidos com “[link=www.blablabla.com.br]link[/link]”, olhando assim bem rápido teremos partes que nunca vão mudar que são “[link=” e “[/link]” e essas partes são muito importante, pois é o começo e o final respectivamente do nosso link, o restante será as informações que o usuário esta querendo informar.
Vamos abrir nosso visualRegexp 3.0, quem não fez o download ainda pode encontrar [link=http://laurent.riesterer.free.fr/regexp/]aqui[/link] hehehehee.
Com ele aberto vamos colar essa ultima frase que eu escrevi na área do “sample” como mostra a figura abaixo.

Vamos começar por algo bem simples, onde faremos só o reconhecimento do “[link=http://laurent.riesterer.free.fr/regexp/]aqui[/link]”, vamos escrever uma ER do tipo “\[link=[\w:/\.]+\][\w ]+\[/link]” onde esperamos algo que inicia com “[link=” seguido de qualquer caractere alfanumérico ou barra ou ponto quantas vezes for necessário seguido de “]” seguido de qualquer caractere quantas vezes necessário seguido de “[/link]”, colocando essa ER no Visual Regexp na parte do pattern (padrão) e clicando em “Go” vamos ter o resultado igual à figura abaixo.

O Regexp sinaliza com cores o que casou com que, e vimos que alcançamos nosso objetivo inicial que era encontrar no texto a parte do link.
Mas vamos precisar dividir em grupos a nossa ER para conseguirmos pegar a URL e a descrição. Então vamos cercar com parênteses a parte da ER que trata da URL e a parte que trata da descrição ficando “\[link=([\w:/\.]+)\]([\w ]+)\[/link\]” vamos executar o Regexp e ver como ele vai exibir os casamentos.

Ele sinalizou em vermelho todo que a ER casou, depois em azul o primeiro grupo e em verde o segundo grupo que nos criamos.
O terceiro passo da criação da ER deve ser feito no Visual Studio por se tratar de uma particularidade do objeto REGEX do .Net e o Visual Regexp não aceita originando um erro.
Mas por hora vamos criar uma aplicação teste para essa nossa ER onde iremos verificar se houve casamento do nosso texto com o nosso padrão, iremos pegar o que casou e imprimir na tela.
using System;
using System.Text.RegularExpressions;
class Program
{
static void Main(string[] args)
{
String EntradaDoUsuario = "Vamos abrir nosso visualRegexp 3.0, quem não fez o download ainda pode encontrar [link=http://laurent.riesterer.free.fr/regexp/]aqui[/link] hehehehee.";
Regex ER = new Regex(@"\[link=([\w:/\.]+)\]([\w ]+)\[/link\]", RegexOptions.None);
if (ER.IsMatch(EntradaDoUsuario))
{
Console.WriteLine(ER.Match(EntradaDoUsuario).ToString());
}
Console.ReadKey();
}
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

No primeiro artigo sobre expressões regulares eu fiz uma introdução bem superficial sobre alguns pontos, na verdade batemos conversamos um pouco sobre o assunto.
Hoje, vamos ver mais alguns pontos e entender algumas coisas contidas dentro de uma ER.
Eu utilizo um aplicativo bem pequeno para criar e testar minhas ERs, ele é free e bem fácil de ser utilizado, para quem quiser fazer o download basta entrar em http://laurent.riesterer.free.fr/regexp/ lá tem atualmente 2 versões, eu utilizo a 3.1.
No momento vamos nos focar na ER em si e não na aplicação dentro do projeto C#, vamos criar essa ER aos pouco e vamos chegar a um resultado esperado.
Uma data tem partes simples de entender, por exemplo, os meses que vão de “01” até “12” nada a mais e nada a menos, temos também os dias que vão de “01” até “28”, “30” ou “31” e por fim os anos que neste momento não vamos nos preocupar.
Uma data valida seria “31/12/2010”, vamos pegar o dia para analisarmos:
1º) No dia podemos observar que o primeiro digito pode ser “0”, “1”, “2” ou “3” e no segundo digito podemos ter de “0” a “9”.
2º) Quando o primeiro digito é “3” só podemos ter no segundo digito o “0” e o “1”.
3º) Quando o primeiro digito é “0” não podemos ter no segundo outro “0”.
Agora vamos analisar o mês.
1º) No primeiro digito podemos ter “0” e “1”.
2º) Quando o primeiro digito é “0” podemos ter no segundo de “1” a “9”.
3º) Quando o primeiro digito é “1” podemos ter no segundo de “0” a “2”.
Tendo esses dados vamos criar uma ER simples sem nos preocuparmos tento com as regras acima e depois vamos parte por parte.
EX1: “\d\d/\d\d/\d\d\d\d”
Nesse exemplo validaremos/casaremos todo conjunto de caracteres que atender esse padrão. Que a primeira vista é confusa e complicada, mas não é. “\d” como já sabemos mapeia qualquer caractere que seja digito, então temos um digito seguido de outro digito seguido por barra “/” seguido de mais 2 dígitos seguidos de uma barra “/” seguidos de mais 4 dígitos. Essa ER casa com “00/00/0000”, “99/99/9999” e “12/34/5678” e não casa com “AA/BB/dddd”.
Mas temos os operadores quantitativos que nos ajudam a informar quantas vezes deve ser mapeado sem ter que ficar colocando “\d” varias vezes para obter esse resultado, imagina se precisássemos validar “0123456789-0987654321” quantos “\d” teríamos que colocar. Para validarmos esse valor/formato podemos escrever uma ER assim “\d{10}-\d{10}”.
Onde “{10}” informa quantas vezes “\d” deve aparecer antes do “-“ e quantas vezes deve aparecer depois.
Vamos refatorar nosso EX1.
Ficando: “\d{2}/\d{2}/\d{4}”, ai temos uma ER que diz 2 dígitos seguidos de barra “/” seguidos de 2 dígitos seguidos de barra “/” seguidos de 4 dígitos, mudamos a ER mais o resultado esperado é o mesmo.
Só lembrando que temos uma lista acima de regras que observamos para a data, então vamos para o primeiro, onde diz quais valores podemos ter para o dia, mas antes vamos refatorar mais uma vez nossa ER, criando os agrupamentos e substituindo “\d” pelo conjunto “[0-9]”.
Ficando: “([0-9]{2})/([0-9]{2})/([0-9]{4})”
Agora sim vamos ajustar nossa ER para alem de validar o formato validar os valores do dia “([0-3][0-9])/([0-9]{2})/([0-9]{4})” desta forma o “99/99/9999” não casa mais.
Vamos pegar agora a parte que fala a regra para o mês “([0-3][0-9])/([01][0-9])/([0-9]{4})” agora o valor “00/20/2010” não casa mais.
É importante criar passo a passo a sua ER e ir validando se está ocorrendo como você deseja.
Estamos em um ponto que a refatoração vai ser mais complicada por isso temos que ter mais atenção, pois temos a regra que quando “0” no primeiro não podemos permitir “0” no segundo, quando “1” ou “2” podemos ter “0” a “9” e quando “3” podemos ter “0” e “1”, vamos colocar em pratica o uso do “|” (ou). Nossa ER vai ficar assim “(0[1-9]|[12][0-9]|3[01])/([01][0-9])/([0-9]{4})” colocamos 3 opções no para o primeiro grupo separados por “|”(ou), no primeiro permitimos “0” seguido de “1” a “9”, no segundo permitimos “1” e “2” seguidos de “0” a “9”e por ultimo “3” seguido por “0” ou “1”.
Praticamente terminamos a validação do dia.
Vamos agora para a validação do mês, lembrando que o primeiro digito pode ser “0” e “1”, quando “0” o segundo poder ser de “1” a “9” e quando o primeiro for “1” podemos ter somente “0”,”1” e “2”, refatorando nossa ER temos “(0[1-9]|[12][0-9]|3[01])/(0[1-9]|1[0-2])/([0-9]{4})”, mais uma vez utilizamos “|”(ou) só que desta vez no 2 grupo, onde dizemos que se o primeiro digito for “0” seguido de “1” a “9” ou “1” seguido de “0” a “2”.
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

Galera! Hoje vamos conversar, já que para falar de expressões regulares temos que ter um cuidado especial, se hoje vai ser seu primeiro contato com esse recurso e eu não tiver esse cuidado, posso fazer com que você nunca mais se interesse por esse assunto, e se já teve um contato e quer se aprofundar mais eu não quero deixar você decepcionado, por isso vamos conversar sobre o assunto e viajar neste mundo de “ninjas”.
Primeiro vamos às terminologias, o termo “expressão regular” é um pouco extensa, então a partir de agora vamos nos referir como ER. Um termo que você pode achar estranho é o “casar” (match) que neste caso não quer dizer juntar em laços matrimoniais com outra pessoa e sim a ação de bater, conferir, combinar, igualar, encontrar, encaixar e equiparar. E para completar essa seção temos o “padrão” (pattern) que é o objetivo que queremos alcançar ao escrever uma ER, casar um padrão esse padrão pode ser uma palavra, frase, linha, ou seja, o que quer que precise ser casado com nossa ER.
Para que servem as ERs? Para dizer algo abrangente, quando definido seu padrão você tem uma lista finita ou não de possibilidade de casamento, por exemplo, a ER “[crv]aio” que pode casar com “caio”, ”raio”e “vaio” essa lista abrange especificamente essas três palavras somente.
Podemos utilizar ER para validar o formato do valor informado pelo usuário em um determinado campo, por exemplo, data, CPF, CEP, telefone, numero IP e tudo que você quiser verificar se está no formado que sua ER espera.
Podemos também procurar uma palavra especifica em um texto, trocar essa palavra por outra (replace com ER), podemos colocar agrupamentos na nossa ER e capturar esse agrupamento.
Para utilizarmos o recurso de ER em C# devemos fazer o uso do namespace System.Text.RegularExpressions.
Vamos ver um exemplo básico do básico:
Regex ER = new Regex("n[ãa]o", RegexOptions.None);
String[] texto = new String[10];
texto[0] = "Eu não quero";
texto[1] = "nao quero mais";
texto[2] = "Quero sim";
texto[3] = "O anao está lá";
texto[4] = "No ano de 1987";
texto[5] = "minimercado";
texto[6] = "mini-mercado";
texto[7] = "super-mercado";
texto[8] = "hiper-mercado";
texto[9] = "hiper mercado";
for (int i = 0; i < texto.Length; i++)
{
string Casou = "casou";
if (!ER.IsMatch(texto[i]))
Casou = "não casou";
Console.WriteLine(string.Format("O texto \"{0,-30}\" [{1}]", texto[i], Casou));
}
Entendendo o que isso faz:
1º) Declaramos nossa ER, a classe Regex que esta dentro do namespace System.Tex
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

Vamos entender a relação entre eles e como podemos facilitar a nossa vida com formatação de texto e informação para os usuários.
Culture especifica a localidade, sistema de escrita, o calendário utilizado e o formato para a data, as cadeias de caracteres de classificação, região entre outras informações.
Ou seja, dependendo da cultura corrente podemos ter uma exibição diferente, por exemplo, se a cultura for “pt-BR” teremos para a formatação de moeda os seguintes resultados “R$ 0.01” para valores positivos e “-R$ 0.01” para negativos se a cultura for “en-US” teremos “$ 0.01” para positivo e “<$ 0.01>” para negativos. Isso significa que se você configurar seu computador para utilizar os padrões inglês(EUA) você vai ter um formato de exibição diferente do meu que esta no padrão português(Brasil).
Vamos descobrir qual a cultura corrente estamos utilizando e já vamos ver um pouco do poder do String.Format().
CultureInfo CT = Thread.CurrentThread.CurrentCulture;
Console.WriteLine(String.Format("|{0,-7}|{1,-20}|", "Nome", "Cultura"));
Console.WriteLine(String.Format("|{0,7}|{1,20}|",CT.Name, CT.NativeName));
A primeira linha pegamos a cultura corrente da thread corrente e colocamos em um objeto do tipo CultureInfo. Na segunda linha temos a impressão de 2 valores “Nome” e “Cultura” utilizando String.Format e a terceira linha faz a mesma coisa que a segunda só modificando os valores e a string de formatação.
Você deve ter observado que o primeiro parâmetro do String.Format() é uma string e aparentemente tem umas coisas estranhas nele, não se preocupe só parece mais na verdade é simples, vamos lá entender.
Temos na segunda linha “|{0,-7}|{1,-20}|”, vamos parte a parte, as barras “|” são texto comum ou seja serão exibidas nesta mesma forma, depois temos “{0,-7}”, as chaves “{“ estão cercando o indexador “0” que define qual dos objetos a serem exibidos ele representa e após a virgula “,” temos “-7” que diz que o espaço reservado para a informação é de sete caracteres e como ele esta negativo será completado após o valor com espaços. Isso é feito igualmente para o “{1,-20}” com a diferença do indexador “1” e a quantidade de caracteres “-20”. Resumindo, temos na primeira posição “Nome”, na segunda “Cultura”, quando executado a segunda linha teremos algo do tipo “|Nome |Cultura |”.
Na terceira linha temos “|{0,7}|{1,20}|”, conforme vimos anteriormente as barras serão exibidos normalmente, temos 2 indexadores “{0,7}” e {1,20}”, com a única diferença que eles estão positivos, isso quer dizer que os espaços em branco serão antes dos valores. Digamos que a cultura esteja como “pt-BR”, teremos então o seguinte resultado: “| pt-br| Portugues (Brasil)|”
Como você pode observar, podemos criar frases com varias partes variando o valor, definir um espaço e ainda definir se será completado com espaços em branco antes ou depois do valor, podemos ter vários valores a ser exibidos, vamos ver mais um exemplo.
Console.WriteLine(String.Format("Data: {0}| Hora: {1}| Data(Hora): {0}({1})",DateTime.Now.ToShortDateString(),DateTime.Now.ToShortTimeString()));
Neste exemplo estamos exibindo a data e a hora atual, observe que “{0}” e “{1}” aparecem 2 vezes cada um, ou seja vamos exibir na mesma frase duas vezes a data e 2 vezes a hora com um texto pré-definido, isso de uma forma direta ficaria.
Console.WriteLine("Data: " + DateTime.Now.ToShortDateString() + "| Hora: " + DateTime.Now.ToShortTimeString() + "| Data(Hora): " + DateTime.Now.ToShortDateString() + "(" + DateTime.Now.ToShortTimeString() + ")");
Ficou meio confuso e com um monte de concatenação.
Bom, vimos que para cada objetos contido no array (segundo parâmetro, terceiro parâmetro e assim por diante) a ser exibido temos um representante para ele na string, vimos também que podemos definir espaços para cada um deles dentro da string e caso menores serão completados por espaços antes ou depois do valor.
Mas não é só isso que podemos fazer com o string.Format(), você já precisou formatar um valor Double com formato moeda, até ai tudo bem, mas você descobriu que tem alguém utilizando uma maquina com uma cultura diferente ou o servidor web que você migrou está com uma cultura diferente e o valor não esta saindo em reais (R$) por exemplo e sim em dólar ($), como resolver isso.
Vamos imaginar que você esteja fazendo assim.
Console.WriteLine(String.Format("{0:C}", 189.99));
Até aqui tudo bem, você não esta utilizando concatenações e muito menos criou uma função para isso e sim utilizando recursos disponíveis no framework. Varias conversões e formatações feitas no sistema por padrão esta utilizado a cultura corrente como provider, como podemos resolver a exibição do valor alterando o provider ou cultura?
Vou mostrar 2 soluções, a primeira é definindo a cultura da thread no inicio da execução, a segunda é definindo a cultura como provider na hora da utilização do string.Format.
1º) No inicio da aplicação e a cada inicio de uma nova thead você define a cultura da seguinte forma.
Thread.CurrentThread.CurrentCulture = new CultureInfo("en-US");
Thread.CurrentThread.CurrentUICulture = new CultureInfo("en-US");
2º) Ou passando como provider para o string.Formt() uma nova cultura já definida, como demonstro abaixo.
Console.WriteLine(String.Format(new CultureInfo("pt-BR"), "{0:C}", 189.99));
Destas formas você controla a cultura utilizada dentro de seu aplicativo, pode ser ela windows form ou web (no caso web se o servidor estiver configurado com uma cultura diferente a que você quer)
Podemos definir varias forma de exibir uma data, um inteiro, um Double e outros.
Abaixo tem uma tabela com as possibilidades de formatos de datas.
|
Especificador |
Formato |
Tipo |
Saida |
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

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 {0} está andando para {1} {2} passo(s)", this.nome, Direcao.ToString(), passos);
}
public void Girar(EGirar Movimento, int grau)
{
Console.WriteLine("O robo {0} está girando para {1} {2}º", 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("{0} 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()
{
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

Esse padrão não requer muitas apresentações, é também é bem simples, vamos pensar o que acontece na vida real... Utilizávamos nas nossas construções civis um padrão de tomadas e plugues, um belo dia saiu o padrão brasileiro de tomadas e plugues, quando você compra um aparelho que atende a essa norma logo pensa, vou ter que comprar um adaptador para adaptar esse plugue a tomada que esta em casa, pois são padrões (modelos) diferentes.
Bom com essa historia eu resumi a vida de um Adapter, que será uma classe intermediaria entre outras duas classes, Plugue e tomada.
Vamos criar um padrão com uma classe tomada e uma classe plugue para este padrão, vamos analisar essas classes.
Primeiro padrão:
#region [Padrao1]
public interface IPadrao1
{
String Nome { get; set; }
void testar();
}
public interface IPadraoTomada1 : IPadrao1
{
void Conectar(IPadrao1 _Plugue);
void Desconectar();
}
public class TomadaP1 : IPadraoTomada1
{
public String Nome { get; set; }
IPadrao1 Plugue;
public TomadaP1()
{
Nome = "TomadaP1";
}
public void testar()
{
if (Plugue != null)
{
Console.WriteLine("{0} está com o {1} conectado!", Nome, Plugue.Nome);
Plugue.testar();
}
else
{
Console.WriteLine("{0} está desconectado!", Nome);
}
}
public void Conectar(IPadrao1 _Plugue)
{
Plugue = _Plugue;
Console.WriteLine("{0} conectado!", Plugue.Nome);
}
public void Desconectar()
{
Plugue = null;
}
}
public class PlugueP1 : IPadrao1
{
public String Nome { get; set; }
public PlugueP1()
{
Nome = "PlugueP1";
}
public void testar()
{
Console.WriteLine("{0} funcionando.", Nome);
}
}
#endregion
Temos duas interfaces (IPadrao1 e IPadraoTomada1), e temos uma classe TomadaP1 que encapsula um Plugue do padrão IPradrao1, e com seus métodos Conectar, Desconectar e Teste. O plugue tem o método Teste.
Agora vamos ver o segundo padrão:
#region [Padrao2]
public interface IPadrao2
{
String Descricao { get; set; }
void Run();
}
public interface IPadraoTomada2 : IPadrao2
{
void Plugar(IPadrao2 _Plugue);
void Desplugar();
}
public class TomadaP2 : IPadraoTomada2
{
public String Descricao { get; set; }
IPadrao2 Plugue;
&n
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

Decorar um objeto de uma determinada classe para obtermos resultados diferenciados no ciclo de vida do nosso sistema. Quando eu digo decorar não é criar varias classes herdando de uma classe abstrata e em tempo de execução criar e instancia essas classes, o Decorate nos permite criar classes decorativas que usaremos em tempo de execução para alterarmos o comportamento e/ou resultado de um objeto de uma determinada classe.
Vamos a um estabelecimento onde são vendidas algumas bebidas, café, leite, chá e pingado, analisando a solução já existente, vimos que existe uma classe café, uma leite, uma chá e uma pingado que contém uma instancia da classe café e uma instancia da classe leite.
#region [Bebidas]
public abstract class Bebida
{
public virtual String Descricao { get; set; }
public virtual Double Custo { get; set; }
}
public class Cafe : Bebida
{
public Cafe()
{
Custo = 1.50;
Descricao = string.Format("Café \t\t1x{0:C} \t{0:C}", Custo);
}
}
public class Leite : Bebida
{
public Leite()
{
Custo = 1.80;
Descricao = string.Format("Leite \t\t1x{0:C}\t{0:C}", Custo);
}
}
public class Cha : Bebida
{
public Cha()
{
Custo = 1.45;
Descricao = string.Format("Chá \t\t1x{0:C}\t{0:C}", Custo);
}
}
public class Pingado : Bebida
{
private Leite _leite = new Leite();
private Cafe _Cafe = new Cafe();
public Pingado()
{
Custo = _Cafe.Custo + _leite.Custo;
Descricao = string.Format("Pingado \n{0} \n{1}", _Cafe.Descricao, _leite.Descricao);
}
}
#endregion
A classe pingado é um sinal que a estrutura está faltando flexibilidade para estendermos as possibilidades de combinações e caso o estabelecimento queira servir leite com chocolate, ou café com menta, da maneira que está hoje teremos que criar varias classes para atendermos essa necessidade.
Ou seja, se queremos colocar menta em todas as bebidas teremos que criar uma classe para cada bebida ficando cafeComMenta, LeitaComMenta e ChaComMenta, imagina se tivéssemos que criar cinco condimentos (Creme, Chocolate, Canela, Menta e Caramelo) terá que criar mais quinze classes, e pensando que poderemos ter combinações do tipo: Leite com Canela e chocolate, a nossa vida seria só criar classes não é verdade?
Bom, analisamos a situação e descobrimos que deveremos mudar um pouco esse cenário, pois não é produto e é fechado para extensão e muito aberto para modificação e isso não é bom.
Existe um principio de projeto que diz: As classes devem estar abertas para extensão e fechadas para modificação.
Pois bem, decidimos não mexer nas classes de bebidas, e sim criarmos classes que vão entender as classes já existentes, de forma a decorar essas classes.
Opa! Decorar uma classe acho que eu já li algo sobre decorar uma classe hoje. Isso mesmo com Decorate pode dar novas características as nossas classes.
Mas vamos parar de tento blábláblá e vamos ver como criar nossos decoradores.
Vamos pegar as classes que já existe no nosso cliente, que são as bebidas que ele trabalha e vamos criar nossas classes decoradoras.
Primeiro criaremos uma classe abstrata para nossos decoradores.
public abstract class Decorador : Bebida
{
protected Double _CustoDecoracao;
protected int _quantidade = 1;
}
Notem que essa classe herda da classe bebida igual todas as bebidas já criadas logo mais verão por que.
A seguir vamos criar as classes decoradoras.
public class Creme : Decorador
{
private Bebida _bebida;
public Creme(Bebida bebida)
{
_bebida = bebida;
_CustoDecoracao = 0.50;
}
public Creme(Bebida bebida, int quantidade)
: this(bebida)
{
_quantidade = quantidade;
}
public override string Descricao
{
get
{
return string.Format("{0} \nCreme \t\t{2}x{1:C} \t{3:C}", _bebida.Descricao, _CustoDecoracao, _quantidade, _CustoDecoracao * _quantidade);
}
}
public override double Custo
{
get
{
return _CustoDecoracao + _bebida.Custo;
}
}
}
public class Chocolate : Decorador
{
private Bebida _bebida;
public Chocolate(Bebida bebida)
{
_bebida = bebida;
_CustoDecoracao = 0.30;
}
public Chocolate(Bebida bebida, int quantidade)
: this(bebida)
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

Mais
uma vez estou aqui para falar de padrões de projetos, e hoje vamos
falar de um padrão que gosta de estar no controle de tudo de ser o
“cara” que chama (invoke) todos os comandos, mas ele mesmo não faz a
operação, curioso para saber mais sobre esse Design Pattern?
Vamos
lá, o Command permite encapsular um objeto e fornecer a outro uma forma
de executar o método do objeto encapsulado de forma dinâmica, o objeto
que da inicio a ação é um controle remoto que tem um comando definido
em um dos seus slots , responsável pela execução do objeto alvo, o
controle remoto, pode ter vários slots e nós podemos configurar cada
slot uma operação diferente, e em qualquer momento modificar a ação do
slot configurando outra operação, vamos também ver mais um pouco de
ligação leve já falado na parte 4 dessa série.
O
cenário é o seguinte, vamos automatizar alguns pontos de nossa casa,
vamos automatizar a luz e ventilador da sala e também a luz e portão
elétrico da garagem, vamos criar um controle com 7 slots cada slot com
dois botões, um ON e um OFF.
Começaremos
pela Interface para os comandos, relembrando ligações leves, são todas
ligações entre objetos onde eles se conhecem muito pouco, só o
suficiente para as chamadas, isso permite uma grande flexibilidade na
criação de nossas classes para utilização dos nossos recursos, neste
caso o controle remoto, onde teremos 3 classes distintas para ser
utilizadas no nosso controle.
public class SemComando : ICommand
{
public void Executar() { }
}
Como
podem ver a interface só vai fornecer o Executar do objeto, ou seja, só
a start da execução, como e o que o objeto vai fazer não importa, o que
importa é que o command vai ser executado pelo controle.
Agora vamos criar a classe responsável pelo controle do todos os comandos.
public class ControleRemoto
{
private ICommand[] _onComando;
private ICommand[] _offComando;
public ControleRemoto()
{
_onComando = new ICommand[7];
_offComando = new ICommand[7];
ICommand semComando = new SemComando();
for (int i = 0; i < 7; i++)
{
_onComando[i] = semComando;
_offComando[i] = semComando;
}
}
public void SetaComando(int slot, ICommand onComando, ICommand offComado)
{
_onComando[slot] = onComando;
_offComando[slot] = offComado;
}
public void OnPressionado(int slot)
{
_onComando[slot].Executar();
}
public void OffPressionado(int slot)
{
_offComando[slot].Executar();
}
public override string ToString()
{
StringBuilder sb = new Str…
[Ver no arquivo exemplo]
return sb.ToString();
}
}
É
essa a classe para criarmos nosso controle, ela é responsável por
armazenar as operações para cada slot e fornecer o método que vai
chamar (invoke) o método Executar() de cada botão, e também fornecer
uma forma de “setarmos” os comandos nos slots, para isso temos um array
do tipo da interface ICommand para ficar a operação do botão ON e um
para o botão OFF de cada slot. Uma curiosidade é no construtor estamos
“setando” todos os slots com um comando default “SemComando”, vamos dar
uma olhada logo abaixo, ele é responsável pela execução do invoke
quando pressionado um botão de um slot vazio.
public class SemComando : ICommand
{
public void Executar() { }
}
Como
sempre para termo uma ligação leve e com a possibilidade de varias
classes participando dessa ligação, fazemos com que elas assinem uma
interface, e como parte do contrato as classes devem implementar todos
os métodos, propriedade e etc. da interface. A classe SemComando vai
nos fornecer a possibilidade de “setar” um slot que tenha um comando já
definido em algum momento para null, ou seja, sem ação.
Agora
vamos criar os nossos objetos alvos, serão classes normais que
sobreviveriam na aplicação, independentes de outras classes, fazendo as
suas operações de forma direta, ou seja, chamando seus métodos de um
objeto instanciado da própria classe.
public class Luz
{
public string _local = string.Empty;
public Luz() { }
public void Ligar()
{
Console.WriteLine("{0} luz ligada", _local);
}
public void Desligar()
{
Console.WriteLine("{0} luz desligada", _local);
}
}
A
primeira será a Luz, uma classe bem simples com a função liga e desliga
bem simples, essa classe não se ligará direto ao controle, ela será
encapsulada em outra classe (Command), mais essa é nossa intenção,
permitindo uma centralização das operações. Vamos ver as demais classes.
public class PortaEletronica
{
public string _local = string.Empty;
public PortaEletronica() { }
public void Abrir()
{
Console.WriteLine("{0} porta aberta", _local);
}
public void Fechar()
{
Console.WriteLine("{0} porta fechada", _local);
}
public void LigarLuz()
{
Console.WriteLine("{0} luz ligada", _local);
}
public void DesligarLuz()
{
Console.WriteLine("{0} luz desligada", _local);
}
}
public class VentiladorTeto
{
public enum Nivel
{
DESLIGADO = 0,
BAIXO = 1,
MEDIO = 2,
ALTO = 3
}
public string _local = string.Empty;
public Nivel _nivel = Nivel.DESLIGADO;
public VentiladorTeto() { }
public void High()
{
_nivel = Nivel.ALTO;
Console.WriteLine("{0} ventilado está com velocidade alta", _local);
}
public void Medium()
{
_nivel = Nivel.MEDIO;
Console.WriteLine("{0} ventilado está com velocidade média", _local);
}
public void Low()
{
_nivel = Nivel.BAIXO;
Console.WriteLine("{0} ventilado está com velocidade baixa", _local);
}
public void Off()
{
_nivel = Nivel.DESLIGADO;
Console.WriteLine("{0} ventilado está desligado", _local);
}
public void Atualizar()
{
switch (this._nivel)
{
case VentiladorTeto.Nivel.DESLIGADO:
 
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

Vamos
falar do padrão Observer, na minha opinião é um dos mais interessantes,
imagina manter os objetos atualizados quando acorrer algo em um objeto
importante. E vamos ver ligações leves entre objetos uma boa pratica de
programação, então vamos lá.
Para
entendermos o padrão Observer, vamos pensar como funciona uma Editora
(Observado) de jornal, eles tem uma lista de clientes (Observadores),
quando sai uma nova publicação todos os observadores recebem uma copia
do jornal, sendo que a qualquer momento um novo cliente(Observador)
pode se registrar ou os clientes atuais cancelarem o registro.
Bom, o padrão Observer é isso, um objeto (Observado) que permite que outros objetos sejam registrados como
observadores ou cancelar o seu registro a qualquer momento da
aplicação, e ressaltando a ligação leve entre o objeto observado e seus
observadores, com isso os objetos podem interagir, mas não sabem quase
nada um sobre o outro, deixando bem flexível os objetos observadores e
observados.
Pensando
em uma aplicação pratica, vamos criar rede de fabricação de automóveis,
onde vamos ter duas montadoras (observados) e varias
fabricas(observadores) e prestadora de serviços(observadores), observe
que teremos 2 classes que farão o papel de observador (poderíamos ter
“n” classes diferentes), onde os fabricas e prestadoras vão se
registrar em uma ou mais montadoras e sempre que a montadora receber um
novo pedido os observadores vão receber uma notificação com a
quantidade.
Vimos
aqui uma dependência um-para-muitos, esse processo de registro e
cancelamento do registro será feito em tempo de execução, podendo a
qualquer momento ficar observando ou não uma montadora, e/ou observar
mais de uma montadora simultaneamente.
No
exemplo abaixo demonstro como implementar essa solução, um outro ponto
importante é que existem varias formas de implementar qualquer padrão,
o que devemos entender de cada um é o conceito, contexto e aplicação.
Temos
que criar um EventArgs para passagem dos parâmetros e a interface para
os observadores e observados se comunicarem, visto que esse é o único
canal e ligação entre observador e observado.
// Argumentos para os Eventos
public class ChangeEventArgs : EventArgs
{
public String Nome { get; set; }
public int Pecas { get; set; }
}
// A interface para os observadores
public interface IObservador
{
String _Nome { get; set; }
void Update(object sender, ChangeEventArgs e);
}
Todas
as classes que querem observar deve implementar a interface
IObservador, lembra da ligação leve, muito bem essa é nossa ligação
leve, o observador não sabe o observado faz e nem o observado sabe o
que o observador faz, a única coisa que um sabe sobre o outro é que
quando houver uma alteração no observado o observador vai ser
notificado, isso vai ser feito pelo método “Update”.
Vamos
criar uma classe abstrata para os observados, aqui vamos definir o
método para registro de observadores e o método de cancelamento, e
também a chamada para notificar os observadores.
// Classe abstrata para criação da montadoras (observados)
public abstract class Montadora
{
protected String _Nome;
protected int _Pecas;
// Construtor
public Montadora(string Nome)
{
this._Nome = Nome;
}
// Evento
protected event EventHandler<ChangeEventArgs> Change;
// Invoke do evento
protected virtual void OnChange(ChangeEventArgs e)
{
if (Change != null)
{
Change(this, e);
}
}
//Metodo para registrar observadores
public void Registrar(IObservador Observador)
{
Change += Observador.Update;
Console.WriteLine("{0} registrado(a) com sucesso na montadora {1}", Observador._Nome, this._Nome);
}
//Médoto para cancelar observadores
public void Cancelar(IObservador Observador)
{
Change -= Observador.Update;
Console.WriteLine("{0} cancelado(a) com sucesso na montadora {1}", Observador._Nome, this._Nome);
}
protected int Pecas
{
get { return _Pecas; }
set
{
if (_Pecas != value)
{
_Pecas = value;
OnChange(new ChangeEventArgs { Nome = _Nome, Pecas = _Pecas });
Console.WriteLine("");
}
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|
Falaremos um pouco sobre design patterns ou
padrões de projetos, um assunto que interessa para programadores .net, java e
outras linguagens OO.
Na Introdução vamos ver um pouco de historia.
Uma definição para Design Patterns pode ser:
“Uma solução para um problema dentro de um contexto”.
Os primeiros design patterns surgiram da
engenharia civil com um trabalho do engenheiro Chistopher Alexander na década
de 70, que catalogou suas experiências em resolver problemas de projetos em
construções gerais publicando os livros Notes on the Synthesis of Form , The
Timeless Way of Building e A Pattern Language , descrevendo cada problema
ocorrido e a base da solução para o problema de uma forma a ser reutilizado em
outros projetos.
Podemos
encontrar vários padrões de documentação para o design patterns, pois existem
autores que preferem utilizar de uma documentação altamente estruturada
(seguindo recomendações de Chistopher [Ler mais em http://pt.wikipedia.org/wiki/Padr%C3%B5es_de_projeto_de_software])
e outras mais descritivas, mais ambas são fáceis de ser entendidas e devem ser
consideradas.
A partir dos
conceitos de Chistopher,
em 1987, os programadores Kent Beck e Ward Cunningham propuseram os primeiros
padrões de projeto para a área da Ciência da computação.
Erich
Gamma, Richard Helm, Ralph Johnson e John Vlissides integrantes da “Gangue dos
Quatro” (Gang of Four) publicaram em 1995 o livro Design Patterns: Elements
of Reusable Object-Oriented Software.
Os padrões “GoF” como é conhecido a “Gang of Four”,
são organizado em 3 grupos distintos:
·
Padrões Criacionais: envolvem a criação de
instancias de objetos, todos fornecem alguma maneira de desconectar o cliente
dos objetos a partir dos quais serão geradas instancias;
·
Padrões Estruturais: permitem que você organize
classes ou objetos em estruturas maiores;
·
Padrões Comportamentais: preocupam-se com a
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|
Vamos falar hoje
sobre os padrões “Gof”, dividindo eles pelas suas famílias e pelo seu atributo,
vamos ver também uma breve descrição desses padrões para podermos ter uma
pequena idéia do que cada um pode fazer para solucionar um determinado problema.
Vamos lá, já vimos
no artigo anterior [link]Design Patterns – Introdução[/link] como surgiu o conceito dos Padrões
de projetos, e conhecemos a “Gangue dos Quatro” agora vamos ver seus padrões.
Lista de padrões
“Gof” organizados nas suas famílias:
·
Criacional:
o
Singleton:
assegura que somente um objeto de uma determinada classe seja criado em todo o
projeto;
o
Abstract
Factory: permite que um cliente crie famílias de objetos sem especificar suas
classes concretas;
o
Builder:
encapsular a construção de um produto e permitir que ele seja construído em
etapas;
o
Prototype:
permite você criar novas instancias simplesmente copiando instancias
existentes;
o
Factory
Mathod: as subclasses decidem quais classes concretas serão criadas.
·
Estruturais:
o
Decorator:
envelopa um objeto para fornecer novos comportamentos;
o
Proxy:
envelopa um objeto para controlar o acesso a ele;
o
FlyWeigth:
uma instancia de uma classe pode ser usada para fornecer muitas “instancias
virtuais”;
o
Facade:
simplifica a interface de um conjunto de classes;
o
Composite:
Os clientes tratam as coleções de objetos e os objetos individuais de maneira uniforme;
o
Bridge:
permite criar uma ponte para variar não apenas a sua implementação, como também
as suas abstrações;
o
Adapter:
envelopa um objeto e fornece a ele uma interface diferente;
·
Comportamental:
o
Template
Method: As subclasses decidem como implementar os passos de um algoritimo;
o
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|
|

Vamos continuar com a série Design Patterns
apresentando o padrão State, não é um padrão com um grau de dificuldade alta
mais não é tão simples como o singleton exibido no ultimo artigo.
O padrão state permite que um objeto altere o
seu comportamento quando o seu estado interno muda. O objeto parecerá ter
mudado de classe.
O padrão encapsula os estados em classes
separadas e delega as tarefas para o objeto que representa o estado atual, nós
sabemos que os comportamentos mudam juntamento com o estado interno.
A baixo temos o diagrama de classe.
 Obs: Diagrama resumido
para termos só o necessário para representação e ficar fácil o entendimento.
Vamos analisar o diagrama.
O contexto é a classe que pode ter vários
estados internos diferentes.
A interface estado define uma interface comum
para todos os estados concretos. Como são intervambiaveis, todos devem
implementar a mesma interface.
Os estado concretos (podemos ter varios estados
concretos) lidam com as solicitações provenientes do contexto. Cada estado
concreto fornece a sua própria implementação de uma solicitação. Assim, quando
o contexto muda de estado, seu comportamento também muda.
Sempre que uma solicitação() é feita ao
contexto, ela é delegada ao estado apropriado para ser processado.
Agora vamos imaginar um cenário, vamos imaginar
uma conta corrente bem simples com opção de depositar e sacar dinheiro e já
imaginamos os estado que essa conta pode estar saldopositivo, saldonegativo e
bloqueado.
Vou exibir uma implementação sem utilizar o
padrão state para mostrar o quanto ficamos amarrados em ifs e cases deixando a
nossa manutenção um pouco complicado pois você pode alterar algo e atrapalhar o
funcionamento de tudo o que já estava funcionando e até mesmo validado.
public enum ContaState
{
saldoPositivo,
saldoNegativo,
bloqueado
}
public class Conta
{
public
Conta()
{
this.Saldo
= 0;
this.MeuEstado
= ContaState.saldoPositivo;
}
public
Conta(Double valor)
{
this.Deposito(valor);
}
public Double
Saldo { get; set;
}
public ContaState
MeuEstado { get; set;
}
public void Saque(Double valor)
{
switch
(MeuEstado)
{
case
ContaState.saldoPositivo:
this.Saldo
-= valor;
Console.WriteLine("Retirado R$ {0}, saldo atual R$ {1}.",
valor, this.Saldo);
if (this.Saldo > 0)
this.MeuEstado = ContaState.saldoNegativo;
break;
case ContaState.saldoNegativo:
this.Saldo
-= valor;
Console.WriteLine("Retirado R$ {0}, saldo atual R$ {1}.",
valor, this.Saldo);
if
(this.Saldo < -100.00)
{
this.MeuEstado
= ContaState.bloqueado;
}
break;
case
ContaState.bloqueado:
Console.WriteLine("Conta bloqueada, saque cancelado, saldo atual R$
{1}.", valor, this.Saldo);
break;
default:
break;
}
Console.WriteLine("Estado da conta: {0}\n", this.MeuEstado.ToString());
}
public void Deposito(Double
valor)
{
this.Saldo
+= valor;
if (this.Saldo <= -100.00)
this.MeuEstado
= ContaState.bloqueado;
else if (this.Saldo >=
0)
this.MeuEstado = ContaState.saldoPositivo;
else
this.MeuEstado
= ContaState.saldoNegativo;
Console.WriteLine("Foi depositado R$ {0}, saldo atual R$ {1}",
valor, this.Saldo);
Console.WriteLine("Estado da conta: {0}\n", this.MeuEstado.ToString());
}
}
Agora vamos aplicar toda teoria que vimos sobre
state, vamos encapsular cada estado em uma classe, e para a alteração o estado
da classe contexto vamos ter uma ação invocada (Saque ou Deposito), veja o
fluxo geral do estou disendo.

E como implementaremos isso?
Primeiro vamos ter que criar uma interface para
os estados.
public interface IContaState
{
void Saque(Double
valor);
void Deposito(Double valor);
}
Teremos só dois metodos, saque e deposito.
Vamos implementar 3 estados fazendo um contrato
com a interface IContaState, você se lembra do enum (saldoPositivo,
saldoNegativo, bloqueado) criado no exemplo sem o padrão? Pois bem vamos ter uma
classe para cada uma daquelas opções.
public class saldoPositivo
: IContaState
{
private Conta _conta;
public
saldoPositivo(Conta PConta)
|
|
03/05/2010 19:18:00
|
|
|
|
|

Continuando com a
série Design Patterns vamos falar sobre Singleton.
Antes de começar a
despejar um monte de informação, vamos criar um cenário...
Você é um
programador solo, que cria o projeto, trabalha sozinho em todos os passos do
mesmo? Ou você trabalha com uma equipe com vários programadores e cada um cria
uma parte do projeto visando um todo para chegar a um único resultado? Em ambos
os caso o singleton será útil, no primeiro vai resolver os casos dos
programadores que esquecem até mesmo os próprios conceitos utilizados na
implementação de uma classe, e no segundo vai garantir que ninguém vai criar
mais de um objeto da mesma classe, vamos ver por quê?
Para alegria geral
na nação, o padrão singleton é o mais simples em termos de seu diagrama de
classe, na verdade o diagrama só contém uma classe.
Digamos que temos
uma classe qualquer que chamaremos de Singleton e queremos que em toda a
aplicação só exista uma única instância dessa mesma classe, e que você tenha
que garantir que isso aconteça, no caso de ser um programador solo, de que você
não se esqueça disso e no caso de uma equipe, que ninguém viole essa regra, bem
com o padrão de projeto Singleton garantiremos uma única instância para a
classe em questão.
Vamos analisar uma
criação de uma classe singleton clássica não thread safe
public class Singleton
{
private static Singleton _unicaInstancia;
public int _valor { get; set; }
// Outras variáveis e propriedade aqui
// Contrutor
privado
private Singleton() { }
public static Singleton getInstance()
{
if (_unicaInstancia
== null)
{
_unicaInstancia = new Singleton();
}
return
_unicaInstancia;
}
public void ExibirValor()
{
Console.WriteLine(_valor);
}
// Outros metodos
aqui
}
Observe que o
construtor é privado não permitindo a criação da classe de fora dela, e que temos
um método getInstance que tem é estática e é esse mesmo método que verifica se
o objeto _unicaInstancia que também deve ser estática já foi instanciado ou se é necessario criar a instancia e retorna
o mesmo para a invocação do método, vamos ver um exemplo utilizando essa
classe.
using System;
class SingletonClient
{
static void Main(string[]
args)
{
Singleton
singCliente1 = Singleton.getInstance();
singCliente1._valor =
10;
Singleton
singCliente2 = Singleton.getInstance();
singCliente2.ExibirValor();
singCliente2._valor = 20;
singCliente1.ExibirValor();
Console.ReadKey();
}
}
Vamos observar as linhas das criações dos objetos singCliente1 e
singCliente2, veja que não utilizamos o new para criações das classes e sim solicitamos ao método getInstance da classe
a única instancia dela. Setamos um valor para a propriedade _valor do
singCliente1 e somente depois criamos o objeto singCliente2 e invocamos o
método ExibirValor do objeto singCliente2, em seguida setamos um valor para a
propriedade _valor do singCliente2 e invocamos o método ExibirValor do objeto
singCliente1.
O resultado na tela do console vai ser:

Por que isso ocorreu se setamos o valor 10 no
objeto singCliente1 e não setamos nada no singCliente2 e ele exibiu o valor do
objeto singCliente1?
Bem, ocorre que ambos os objetos é uma referência
o objeto estático que está dentro da classe, esse objeto é o único objeto
instanciado em todo o projeto, o que foi feito, foi criar um ponto global de
acesso a esse objeto.
Como foi dito a solução acima não vai ter o resultado
esperado quando u
...
Exibição do post interrompida. Para ler conteúdo completo, clique aqui
|
|
|