Skip navigation

Objetos ou Estruturas de dados? A pergunta surge pelo fato de que embora hoje existam linguagens e ferramentas que dão total suporte ao desenvolvimento orientado a objetos, nem todos os desenvolvedores  fazem uso de todos os recurso que a OO oferece. A Orientação a objetos nos diz que “objetos são representações de personagens do mundo real” e “objetos reúnem dados e comportamento”, mais ao contrário destas definições o que vemos é o que mostra a figura abaixo:

O que vemos na imagen acima, é o que a anos vem sendo  feito em questão de modelagem de software. As classes, ao invés de serem representações de personagens do mundo real, passam a ser a representação das tabelas do banco de dados, indo totalmente contra os princípios da orientação a objetos. Pode parecer muito purismo, mais quando se trata de software temos questões como manutenção, evolução e correção de erros; uma vez utilizando abordagens como a demostrada acima, estas tarefas se tornam muito difíceis e custosas de se fazer.
Objetos x Estruturas de Dados

Como identificar quando temos um objeto e quando temos uma estrutura de dados? É simples como na figura mostrada anteriormente, o que temos é uma estrutura de dados que é uma classe que expõe seus atributos, onde o consumidor da classe pode livremente acessar suas propriedades e modifica-las; Já quando temos objetos, os mesmos, não permitem que seus dados sejam modificados diretamente, mais expõem métodos que efetuam tais mudanças, ou seja, quando o consumidor da classe deseja realizar alguma operação no objeto em questão, ele chama um de seus métodos para realizar tal tarefa. Observe o exemplo abaixo, de como ficaria o cenário abordado na figura anterior contemplando a orientação a objetos:

Observe o código abaixo da classe cliente:

O primeiro detalhe no código acima é o seguinte: as propriedades da classe não podem ser escritas diretamente, isto faz com que tenhamos que expor métodos que serão utilizados quando o consumidor da classe quiser efetuar alterações no estado do objeto. Temos o exemplo da propriedade Endereco e Telefone, que possuem métodos que efetuam a escrita nas propriedades já que isto não pode ser feito diretamente. O construtor parametrizado, recebe como parâmetro dados que são obrigatórios na criação do objeto, como por exemplo TODO cliente precisa ter um nome. Talvez você esteja se perguntando: estamos trabalhando igual ao java que não tem propriedades? Trabalham com métodos get e set? Não estamos utilizando REALMENTE a orientação a objetos, e isto quer dizer que não devemos dizer a um objeto o que ele deve fazer, que é quando temos acesso diretamente aos seus atributos, mais pedir que ele faça tal tarefa, que é quando chamamos os métodos expostos por ele. E note que o diagrama mostrado anteriormente, além de mais organizado, está realmente se comportando como o espelho de personagens do mundo real e traduzindo em objetos, e não é mais um espelho das tabelas de um banco de dados. Vale ressaltar que, isto vale também para as regras de negócio à que estejam relacionado  o objeto em questão, e não somente aos seus
atributos. Veja o exemplo abaixo:



 

Imaginando que este método esteja em uma classe pedido, ele está realizando uma validação de negócio, em que não pode ser adicionado um item de pedido em que quantidade seja zero.

Trabalhando levando em consideração os princípios da orientação a objetos, temos várias vantagens que nos fazem ter certeza, que esta forma de trabalhar é muito melhor do que o método convencional, em que os desenvolvedores enxergam os objetos apenas como espelho do banco de dados. Se os princípios forem utilizados corretamente, os benefícios que ele traz irão aparece através de uma manutenção mais rápida e evolução mais eficiente.

Bom Pessoal , espero que tenham gostado do artigo, e que ele possa colaborar com o crescimento e evolução profissional de cada leitor, abraços e até a próxima.

 

   Bom pessoal hoje, vamos implementar do zero o pattern de arquitetura Registry. O Registry nada mais é do que uma espécie de buscador de objetos, ou seja, um localizador. O Registry sabe onde se encontram os objetos que você precisa, esta é a função dele. Você pode utilizá-lo, quando houver a necessidade de ter um objeto que sabe procurar e achar os objetos que precisam ser localizados e utilizados. O registry também é importante, por que com ele você pode obter inversão de controle, ou seja, você passa a ele o controle e responsabilidade de encontrar os objetos; você apenas solicita a ele e o mesmo retorna o objeto para você. Mais chega de blá, blá blá e vamos meter a mão na massa. Olhe o diagrama abaixo:

    Vamos começar a “discecar” a solução. Veja que tenho uma classe registry, que será chamada por qualquer camada, haja vista, o registry também poder ser utilizado como um service locator e desta maneira poder ser acessado por qualquer camada da aplicação. Ele faz uso de um container, que é quem armazena os objetos que implementam as abstrações, o registry irá solicitar o container que resolva uma determinada abstração( inteface ou classe abstrata ); note que estamos aqui utilizando a inversão de controle, o registry não faz referencia a uma implementação, e sim a uma abstração de um contaner. Exitem vários containers no mercado, structured map, castle windsor, unity da microsoft enfim uma infinidade de containeres de ibnjeção de dependência. O fato de apontarmos para uma abstração faz com que, independende do container, o que importa e existir alguém, a quem o registry possa pedir para resolver a abstração. Temos ainda uma classe para nos auxiliar a obter as abstrações e suas repectivas abstrações.
 
O Registry
     Veremos o código do registry abaixo:

 
    Note que o container aponta para uma abstração de um container, ou seja, não importa quem ele é o importante é ele ser capaz de resolver a dependência/abstração. Dentro do construtor, é instânciada uma implementação da interface IDIContainer que utiliza o Unity da microsoft para container de injeção de dependência. É responsabilidade do container, armazenar as abstrações( interfaces/classes abstratas) para que possam ser recuperadas quando necessário.
 
IDIContainer
 

     Como dito anteriormente, a função do container é simplesmente armazenar as abstrações e suas respectivas implementações,  Veja o código abaixo:

  Veja que o contrato é simples, um método para registrar a abstração, a alguma classe que a implemente, e um método para recuperar alguma classe que resolva, ou seja, implemente uma determinada abstração.
 
Implementando o IDIContainer

     A implementação não tem nenhum mistério, precisamos apenas obter as classes e abstrações, referenciados no projeto em que se encontra o container veja o código da implementação para o Unity abaixo:

     A implementação consiste apenas em encontrar as classes e abstrações e mapear no container, no caso desta implementação do Unity. Veja no construtor é chamado o método registraClasses, que usa a classe AssemblyHelper para obter todas as abstrações referenciadas no projeto, mapeando para as respectivas implementações. Implementação da interface:

Métodos

Register Type: Registra a abstração para uma implementação.

Resolve: retorna uma implementação de uma determinada abstração.

 

AssemblyHelper

     A classe Assemblyhelper, recupera todas as abstrações e implementações, referenciadas no projeto em que se encontra a implementação do container. É importante para que o registry possa utilizar o container, que você referencie as dll´s em que se encontram as classes e interfaces que você deseja mapear. Código do Assemblyhelper abaixo:

 

public class AssemblyHelper

{

    public IList<Assembly> obterAssemblies()

    {

        var listAssemblyRetorno = new List<Assembly>();

        var objDirInfoRelease = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory);

        var objDirInfoBin = objDirInfoRelease.Parent;

        var arquivoDLL = objDirInfoRelease.GetFiles();

        foreach (var fileInfo in arquivoDLL)

        {

            if (fileInfo.FullName.Contains(“.dll”))

            {

                Assembly objAssembly = Assembly.LoadFrom(fileInfo.FullName);

                listAssemblyRetorno.Add(objAssembly);

            }

        }

        return listAssemblyRetorno;

    }

    public IList<Type> obterClassesPorAssembly(Assembly pAssembly)

    {

        IList<Type> listaClassesAssembly = new List<Type>();

        foreach (var vType in pAssembly.GetTypes())

        {

            if (vType.IsClass)

            {

                listaClassesAssembly.Add(vType);

            }

        }

        return listaClassesAssembly;

    }

    public IList<Type> obterInterfacesPorAssembly(Assembly pAssembly)

    {

        IList<Type> listaInterfacesAssembly = new List<Type>();

        foreach (var vType in pAssembly.GetTypes())

        {

            if (vType.IsInterface)

            {

                listaInterfacesAssembly.Add(vType);

            }

        }

        return listaInterfacesAssembly;

    }

    public IList<Type> obterAbstracoesPorAssembly(Assembly pAssembly)

    {

        IList<Type> listaInterfacesAssembly = new List<Type>();

        foreach (var vType in pAssembly.GetTypes())

        {

            if (vType.IsInterface)

            {

                listaInterfacesAssembly.Add(vType);

            }

            else if (vType.IsClass && vType.IsAbstract)

            {

                listaInterfacesAssembly.Add(vType);

            }

        }

        return listaInterfacesAssembly;

    }

    public IList<Type> listaImplementacoesAbstracao(Type pTipoInterface)

    {

        IList<Type> listaImplInterface = new List<Type>();

        foreach (var vAssemblies in this.obterAssemblies())

        {

            foreach (var vClasse in this.obterClassesPorAssembly(vAssemblies))

            {

                if (vClasse.GetInterface(pTipoInterface.Name) != null)

                    listaImplInterface.Add(vClasse);

            }

        }

        return listaImplInterface;

    }

    public IList<Type> obterAbstracoesNosAssembliesReferenciados()

    {

        IList<Type> listaAbstracoes = new List<Type>();

        foreach (var vAssemblies in this.obterAssemblies())

        {

            foreach (var vInterface in this.obterAbstracoesPorAssembly(vAssemblies))

            {

                listaAbstracoes.Add(vInterface);

            }

        }

        return listaAbstracoes;

    }

    public bool TypeFilter(Type pTipo, object pObjetoFiltro)

    {

        return pTipo.Name == pObjetoFiltro.GetType().Name;

    }

}

     Um detalhe importante na implementação deste pattern, é que além de ter um objeto localizador, procurei separar responsabilidades. Se você notar cada classe faz o seu papel, e pede que as outras colaborem quando necessário, é ai que vemos como princípios como o da responsabilidade única, inversão de controle e injeção de dependência tem seu valor; agora se amanhã mudarmos de container e quisermos utilizar o Castle Windsor, por exemplo, basta apenas criar uma classe que implemente a interface IDIContainer e mudar uma linha de código no construtor do registry, exemplo:

 

 public Registry()

{

   this.Container = new WindsorDIContainer();

}

     Bom pessoal vamos ficando por aqui, espero que vocês tenham gostado do artigo, e me coloco a disposição para quaisquer esclarecimentos. Abraços e até a próxima.

 Bom pessoal até aqui, vimos criação do binding, fluxo de dados, conversão de dados, os 4 elementos que compõem o mecanismo de binding, enfim já apredemos bastante, mais ainda não acabou. Nesta parte final, iremos aprender sobre binding com coleções, validação e finalizar esta série de artigos que teve por objetivo, passar o entendimento de como o mecanismo de databinding dentro do WPF é diferenciado, como ele pode ser um aliado poderoso na construção de aplicações corporativas.

 
Efetuando o Binding com Coleções

     Até aqui, abordamos cenários em que o binding é feito utilizando como objeto fonte (source), um objeto único que contém várias propriedades que podem ser utilizadas. Mais existem cenários, em que a necessidade em questão, seja utilizar um conjunto de objetos e não somente um único objeto como fonte de dados; a partir deste conjunto de objetos realizar um filtro, pesquisa ou até mesmo um agrupamento de informações. É justamente em cenários como este, que entra em ação o Binding com coleções.  Controles com a propriedade ItemsControl como ListBox, TreeView ou ListView são comumente usados para visualizar estas coleções. Atente para o diagrama abaixo:

    Note que o diagrama utilizado, é como os que foram utilizados nos artigos anteriores, ou seja, você liga a propriedade ItemsSource( propriedade de destino – target ) a uma coleção de objetos como fonte de dados. Note que a ligação é OneWay e a propriedade ItemsSource, suporta binding por omissão. Veja o exemplo abaixo:

 

A classe Tarefa utilizada no exemplo:
 
 
O code-behind da janela do exemplo:
 
     Na primeira figura, vemos destacado em vermelho, a declaração do objeto fonte de dados(source), através da declaração Source=Tarefas, que é uma propriedade da janela que guarda uma Coleção de objetos do tipo Tarefa; E destacado em azul, a declaração de qual propriedade terá seu valor utilizado. Veja que o binding com coleções é simples, semelhante ao binding para um objeto único, exceto pelo fato de que o objeto fonte de dados, passa a ser um conjunto de objetos e não somente um objeto único.
     É possível fazer utilizar e iterar sobre qualquer coleção, que implemente a interface IEnumerable. Uma funcionalidade interessante,  é que podemos ser notificados quando um item em uma determinada coleção é adicionado, ou retirado. Para que venhamos receber esta notificação, e a mesma refletir na tela para o usuário, temos que utilizar coleções que implemente a interface INotifyPropertyChanged. O WPF fornece algumas destas coleções como ObservableCollection<T>, BindingList<T>, Collection<T> ou até mesmo a famosa List<T>.
 
CollectionViews
 
     Como foi dito no inicio do artigo, você pode querer filtrar, classificar agrupar, enfim realizar alguma ação relacionada ao conjunto de objetos que você possui como fonte de dados; Para poder fazer isto você precisa utilizar coleções que implemente a interface IcollectionView e ligá-la a seu ItemControl.

     CollectionViews, é uma camada sobre a coleção de dados utilizada como fonte de dados, que permite que você realize operações nos objetos da coleção, sem ter que mudar a coleção de origem, ou seja, você pode avegar ou filtrar os objetos e a coleção de origem dos mesmo, não será alterada. A CollectionView, também tem um ponteiro para o item atual da coleção, como mostra a figura abaixo:

 

    Um fato interessante, é que por utilizar a collection View não mudar a coleção de destino, você pode ter na mesma tela, um controle que exibe os dados de uma forma, e outro utilizando a mesma coleção exibindo os mesmos dados de outra. Por exemplo você pode ter um DataGrid com todos os funcionários ordenado por nome e um outro DataGrid com os funcionários ordenados por número de venda. Chega de falatório mão na massa.
     Uma maneira de utilizar CollectionViews, é istânciar um objeto do tipo CollectionViewSource e utilizá-lo como Source. Observe o exemplo abaixo, o Binding é configurado apontando para o objeto CollectionViewSource, ao invéz de apontar para a coleção diretamente, o exemplo abaixo mostra claramente isto:

 

1º É instanciado declarativamente um objeto do tipo CollectionViewSource, que será utilizado como source pela ListBox. O Binding é configurado por omissão {Binding}, ou seja, os dados serão obtidos em tempo de execução. E vejam que tem um agrupamento configurado e apontando para a propriedade Nome da Turma.
 
2º É declarado um DataTemplate( falaremos mais adiante ), que será utilizado pelos itens da ListBox.
 
3º O Binding não está apontando para a coleção diretamente, ao invés disto, ele aponta para o objeto CollectionViewSource de nome colecaoTurmas.
 
4º Foi específicado na ListBox, qual template será utilizado para o agrupamento, no caso o template de nome TurmaTemplate.
 
5ºEstá sendo declarado dentro da listbox, um DataTemplate, para cada item da listbox, no caso apontando para uma propriedade, dentro da classe Turma, que é uma coleção de alunos. Sendo configurado ainda que no Textblock a propriedade a ter seu valor utilizado, é a propriedade Nome, da classe aluno.
 
     No caso, se fosse necessário utilizar a mesma coleção, mais com outra visão ou agrupamento, seria necessário apenas declarar outro objeto CollectionViewSource com outro nome, e utilizar em um outro controle, mais apontando para a mesma coleção.
 
Tipo de Coleção Source
Tipo de Collectionview
Notas
Um tipo interno baseado em CollectionView
Não permite agrupar itens
ListCollectionView
O mais rápido
BindingListCollectionView
Ação
    
 
Classificação de Coleções
 

     Como foi dito no inicio do artigo, é possivel aplicar uma ordem aos itens da coleção. A CollectionViewSource, permite que seja alterada a ordem em que estejam os itens da coleção, cmo também, estabelecer uma nova ordem a partir de critérios. Veja o exemplo, que está sendo realizada uma ordenação pela categoria e pela data inicial:

 

private void AddSorting(object sender, RoutedEventArgs args)

{

    listingDataView.SortDescriptions.Add(

        new SortDescription(“Categoria”, ListSortDirection.Ascending));

    listingDataView.SortDescriptions.Add(

        new SortDescription(“DataInicial”, ListSortDirection.Ascending));

}

 
Filtragem
 

     Outro recurso muito útil é a possibilidade de realizar filtros na coleção. E com estas capacidades, você pode ter controles distintos utilizando a mesma coleção, sendo que um controle mostra os dados da coleção de uma forma, sendo que o outro pode mostrar as informações a partir de um filtro feito sobre a mesma. Observe o exemplo abaixo, em que é aplicado um filtro na coleção, em que só serão obtidos os pedidos com valor acima de R$100,00:

 

listingDataView.Filter += new FilterEventHandler(MostraSomentePedidosValorAcimaCem);

Manipulador do evento

private void MostraSomentePedidosValorAcimaCem (object sender, FilterEventArgs e)

{

    Pedido objPedido = e.Item as Pedido;

    if (objPedido != null)

    {

        if (objPedido.Valor > 100)

        {

            e.Accepted = true;

        }

        else

        {

            e.Accepted = false;

        }

    }

}

 
Agrupamento

     O Agrupamento, permite que a CollectionView particionar os itens da coleção em grupos lógicos. Os grupos lógicos podem ser implícitos ou explícitos. Explicito quando o usuário fornece uma lista de grupo e Implícitos quando os grupos são gerados dinamicamente dependendo dos dados. O exemplo abaixo mostra o agrupamento por categoria:

 

PropertyGroupDescription objGroupDescription = new PropertyGroupDescription();

groupDescription.PropertyName = “Categoria”;

listingDataView.GroupDescriptions.Add(groupDescription);

 
DataTemplates

     DataTemplates são templates, que podem ser aplicados a itens dentro de um controle. Os DataTemplates são muito úteis, quando você deseja que os dados sejam exibidos de alguma forma que não seja a habitual, podendo assim até alterar a aparência, cor de fundo e outras características de um item de uma ListBox por exemplo. Olhe a figura abaixo:

 

   Veja que o DataTemplate, está apontando para um tipo Aluno, e que o template contém um stackPanel de orientação horizontal e um TextBlock que irá mostrar o nome do aluno. Este template mostrado acima, será aplicado a cada item que for adicionado ao ListBox, que será preenchido com uma coleção de objetos do tipo Aluno. Os DataTemplates são muito poderosos e úteis, podendo serem configurados de acordo com a necessidade da aplicação.     Bom Pessoa, chegamos ao fim desta nossa série sobre o Mecanismo de Binding no WPF. Espero ter ajudado e contribuído de alguma forma para o crescimento profissional de cada leitor. Um abraço e até a próxima.

Bom pessoal, seguimos no aprendizado sobre a arquitetura WPF. E nesta segunda parte do estudo sobre o Databinding, iremos aprender como utilizá-lo efetivamente, de maneira prática e fácil.

     Até aqui, vimos os conceitos sobre o Databinding, como ele se diferencia do mecanismo de databinding tradicional e entendemos alguns conceitos importantes sobre o mesmo; entendemos como as  4 peças fundamentais no mecanismo de binding se relacionam, a direção do fluxo dos dados e como é desencadeada as atualizações de fonte dentro do mecanismo de binding. Já falamos muito , mão na massa.
 
Criando o Binding

     Recapitulando o nosso aprendizado, temos os quatro componentes que compõem o mecanismo de binding: objeto que será a fonte dos dados( source ), o objeto que será o alvo( target ), a propriedade de destino( targe property ) e a propriedade dentro do objeto fonte que será utilizada como caminho até o valor a ser utilizado( Path ). Vejamos o seguinte exemplo para fins de demonstração. Suponhamos que temos um objeto cliente, como uma propriedade string e que desejo utilizá-lo em um textbox, observe abaixo o XAML de exemplo:

   No pequeno trecho de código XAML  acima, vemos os 4 componentes obrigatórios do binding em ação. A classe Pessoa é o objeto fonte de dados( source ), o objeto Textbox como objeto de destino( target ), a propriedade nome da classe Pessoa como proprieade que contem o valor a ser usado( Path ) e por fim a propriedade Text da classe TextBox como propriedade de destino( target property ). Para ilustrar melhor olha como ficaria um diagrama do exemplo acima:

    Perceba que no objeto Texbox, não especificamos o Source, ou seja, isto chama-se Binding por omissão. Por não especificar o source, o objeto Textbox herda o Source do seu objeto Pai, sendo necessário apenas especificar a propriedade Path em que o valor da mesma será utilizado e a propriedade destino no caso a propriedade Text.
 
Entendendo o Binding Source
 

     Entender como especificar o BindingSource é muito importante, pois sem uma fonte para os dados não seria possível fazer absolutamente nada. O exemplo de código anterior, o DataContext é especificado somente para o objeto Grid, isto quer dizer que todos os objetos filho de Grid herdam o seu DataContext. Existem várias maneiras de se especificar o BindingSource, ou seja, a origem dos dados a serem utilizados. O Binding por omissão é útil, quando queremos ligar vários objetos utilizando propriedades de uma mesma fonte, mais você pode especificar diretamente no objeto de destino o objeto fonte de dados( Binding Source ), conforme ilustra  a figura abaixo:

     O objeto fonte de dados, pode ainda ser especificado utilizando-se a propriedade da classe Binding chamada ElementName. Conforme ilustra a figura abaixo, o objeto Textblock está ligado ao objeto Textbox atravéz desta propriedade,fazendo com que tudo que é digitado na caixa de texto apareça no Textblock.

 

 
A Propriedade Path
 
    Se a sua fonte de dados é um objeto de negócios, você utilizar a propriedade da classe Binding, chamada Path para indicar o valor a ser utilizado pelo Binding.O primeiro exemplo neste artigo ilustra bem isto, em que o objeto de fonte de dados é um objeto de negócios chamado pessoa e a propriedade utilizada pelo Textbox é a propriedade nome.
 
Dica Importante
 
     Quando é utilizada a ligação vazia, ItemsSource{Binding}, o objeto em questão que utiliza esta declaração, herda o DataContext do objeto Pai, podendo fazer uso de qualquer propriedade do objeto fonte de dados que está ligado ao objeto pai.
 
ValueConverters  

     Observe o seguinte exemplo:

 
 

 

 A propriedade Background da classe Button é do tipo Brush, mais está sendo atribuído um valor do tipo string a ela. Talvez você esteja se perguntando como é que funciona isto? Uma propriedade que é do tipo Brush, estar sendo associado a ela um valor do tipo string e não dar exceção? Não é mágica, isto se deve graças aos TypeConverters, que fazem com que haja uma conversão de um determinado tipo, para o tipo correto da propriedade. Veja o diagrama abaixo:

Os TypeConverters podem serem construindo através da implementação da interface IValueConverter. Como o exemplo de código abaixo:

[ValueConversion(typeof(Color), typeof(SolidColorBrush))]

public class ColorBrushConverter : IValueConverter

{

public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

{

Color color = (Color)value;

return new SolidColorBrush(color);

}

public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)

{

return null;

}

}

 São classes como estas, que permitem a “mágica” mostrada no exemplo funcionar, onde o valor de uma prpriedade do tipo string por exemplo, consiga ser atribuída a uma propriedade cujo valor é do tipo Brush.     Bom pessoal, assim terminamos mais uma parte deste assunto muito importante dentro da arquitetura WPF, que é o Binding. Espero que vocês esteja conseguindo acompanhar e atentar para os detalhes do mecanismo de Binding que são extremamente poderosos e úteis na hora de realizar a ligação dos dados em uma aplicação WPF. Até a próxima pessoal.

O mecanismo de DataBinding, não é novo já existe há algum tempo, mais diferente do mecanismo de DataBinding tradicional, dentro da arquitetura WPF o DataBinding traz alguns recursos diferenciados e que tornam o mesmo, um mecanismo extremamente poderoso, eficaz e que tem papel muito importante na Arquitetura WPF e na construção de aplicativos com esta tecnologia. Neste primeiro artigo estaremos apresentando em detalhes, como tirar proveito deste recursos extremamente poderoso.

     O DataBinding no WPF, entre muitas outras coisas, dispõe de propriedades que tem suporte nativo ao binding, uma representação flexível de dados para o usuário, permite classificar, filtrar e além destas características permite uma clara separação da lógica de negócios da interface com o usuário.
 
O DataBinding

    A definição de databinding é simples: “é  o processo de conectar o aplicativo de interface com o usuário a lógica de negócios”. Embora seja simples esta definição, realizar esta conexão envolve tarefas como validação, conexão com a fonte de dados, apresentação correta e organizada das informações para uma melhor visualização. E uma grande vantagem do binding dentro do WPF, é que ele traz uma vasta gama de propriedades e fontes de dados que podem ser utilizadas nas aplicações.  Vamos começar a entender melhor como este mecanismo funciona. Observe a figura abaixo:

 
A figura acima ilustra o processo de databinding. Veja que é simples, porém muito poderoso o mecanismo de binding. Vamos cmeçar a identificar as peças dentro deste processo. Sempre existirá um objeto fonte( Source ) e um objeto alvo( Target ). Independente do alvo ou fonte o mecanismo de binding sempre seguirá o esquema ilustrado acima.     O mecanismo de binding é composto além dos objetos de fonte e destino, por mais dois outros elementos, que são a propriedade de destino e um caminho para o valor no objeto fonte( source ) para uso, totalizando ao todo quatro elementos. Observe a figura abaixo:
 

 

Identificando na figura acima:
1º Objeto utilizado como fonte de dados( Source ).
2º Objeto de alvo( Target ).
3º Propriedade que terá seu valor utilizado pelo objeto de alvo( Target ), ou seja, o valor desta propriedade é o Path, ou, o caminho em que se encontra o valor a ser utilizado.
4º Propriedade de destino( Target ), ou seja, a propriedade que receberá o valor da propriedade do objeto utilizado como fonte de dados.
 
    Estes quatro elementos, são as peças chaves do mecanismo de binding. Os objetos podem até ser alvos e fontes diferentes, mais de qualquer maneira eles sempre irão se enquadrar neste mecanismo: Objeto Fonte( Source ), Objeto alvo( Target ), propriedade fonte e propriedade de destino.
 
O DataBinding e a direção do fluxo dos dados
 

     Um dos diferenciais do binding na arquitetura WPF é a maneira como o fluxo de dados trafega entre o alvo ( Target ) e o Fonte ( source ). O fluxo de dados pode ser OneWay, TwoWay e OneWayToSource. Observe a figura abaixo.

 

 

O fato de existir diversas formas de direcionar o fluxo dos dados, se deve ao fato das necessidades que existem de comunicação do usuário e a fonte de dados. Você pode, por exemplo, desejar que o usuário ao realizar uma atualização, venha propagar a mesma para a fonte de dados, ou objeto que é a fonte de dados somente atualiza o objeto alvo e não deseja ser notificada se o usuário realiza uma alteração, enfim de acordo com a necessidade, você especifica como será a direção do fluxo de dados. Veja a descrição abaixo de cada uma das formas de trafegar o fluxo de dados;

 

OneWay – Faz com que a propriedade de origem( source ) atualize automaticamente a propriedade de destino( target ), mais não notifica a propriedade de origem caso haja uma atualização na propriedade de destino.

TwoWay- Faz com que tanto a propriedade de origem( source ) ou destino( target ), sejam notificadas caso haja uma alteração em uma ou outra. Este tipo de fluxo de dados é indicado para cenários mais iterativos, quando existe uma necessidade de que atualizações sejam refletidas automaticamentes, ou seja, na fonte( source ) ou no destino(target) que pode ser, um formulário por exemplo. 

OneWayToSource-É o inverso do OneWay, permitindo somente que a propriedade de destino( Target ) atualize a propriedade fonte( Source ).

OneTime –  Embora não ilustrada acima, o OneTime é utilizado quando vc deseja inicializar a propriedade de destino, mais qualquer atualização posterior não seja refletida. Podemos dizer que o OneTime, é um OneWay mais simples.

 

     Você pode especificar o tipo de fluxo de dados, através da propriedade Mode da classe Binding:

<Bnding Mode=OneWay />

 

O que faz propagar a atualização da fonte

 

     Agora que entendemos como funciona o fluxo dos dados entre a fonte e o destino, precisamos saber o que faz desencadear esta atualização ou estas notificações de mudança.

    Os fluxos OneWayToSource e TwoWay, escutam mudanças na propriedade de destino(target) e propagam até a fonte de dados(source), isto é chamado de atualização da fonte. Mais como se dá esta atualização? É simples a propriedade UpdateSourceTrigger da classe Binding, é responsável por específicar como irá ocorrer esta notificação. Observe a figura abaixo: O fato de existir diversas formas de direcionar o fluxo dos dados, se deve ao fato das necessidades que existem de comunicação do usuário e a fonte de dados. Você pode, por exemplo, desejar que o usuário ao realizar uma atualização, venha propagar a mesma para a fonte de dados, ou objeto que é a fonte de dados somente atualiza o objeto alvo e não deseja ser notificada se o usuário realiza uma alteração, enfim de acordo com a necessidade, você especifica como será a direção do fluxo de dados. Veja a descrição abaixo de cada uma das formas de trafegar o fluxo de dados;

 

OneWay – Faz com que a propriedade de origem( source ) atualize automaticamente a propriedade de destino( target ), mais não notifica a propriedade de origem caso haja uma atualização na propriedade de destino.

TwoWay- Faz com que tanto a propriedade de origem( source ) ou destino( target ), sejam notificadas caso haja uma alteração em uma ou outra. Este tipo de fluxo de dados é indicado para cenários mais iterativos, quando existe uma necessidade de que atualizações sejam refletidas automaticamentes, ou seja, na fonte( source ) ou no destino(target) que pode ser, um formulário por exemplo. 

OneWayToSource-É o inverso do OneWay, permitindo somente que a propriedade de destino( Target ) atualize a propriedade fonte( Source ).

OneTime –  Embora não ilustrada acima, o OneTime é utilizado quando vc deseja inicializar a propriedade de destino, mais qualquer atualização posterior não seja refletida. Podemos dizer que o OneTime, é um OneWay mais simples.

 

     Você pode especificar o tipo de fluxo de dados, através da propriedade Mode da classe Binding:

<Bnding Mode=OneWay />

 

O que faz propagar a atualização da fonte

 

     Agora que entendemos como funciona o fluxo dos dados entre a fonte e o destino, precisamos saber o que faz desencadear esta atualização ou estas notificações de mudança.

    Os fluxos OneWayToSource e TwoWay, escutam mudanças na propriedade de destino(target) e propagam até a fonte de dados(source), isto é chamado de atualização da fonte. Mais como se dá esta atualização? É simples a propriedade UpdateSourceTrigger da classe Binding, é responsável por específicar como irá ocorrer esta notificação. Observe a figura abaixo:

Se o valor da propriedade UpdateSourceTrigger for PropertyChanged, a fonte( source ) é atualizado caso haja mudança na propriedade de destino( Target ). Se o valor e UpdateSourceTrigger for LostFocus,  a fonte é atualizado com o novo valor, assim que a propriedade de destino( Target ) perde o foco.     Bom pessoal, neste primeiro artigo de 2 que serão feitos sobre o binding, aprendemos o conceito do binding, a direção do fluxo de dados, como é desencadeada a atualização da fonte de dados e tivemos uma pequena introdução sobre esta importante funcionalidade do WPF. Mais fiquem ligados ainda temos que aprender sobre como criar o binding, binding com coleções, validação enfim tem muita coisa boa por vir. Abraços e até o próximo artigo.

 

    Não é novidade, que a cada dia vemos inúmeras aplicações com interfaces avançadas  e cada vez mais sofisticadas surgindo no mercado. Com o crescimento deste tipo de aplicação, que atende pelo nome de Rich Internet Application ou aplicações de internet ricas( RIA ), surgem novas necessidades, , tecnologias para construção e também novo desafios.  E este desafio se dá, pelo fato de não estarmos trabalhando da maneira tradicional, e passando a expor do lado do cliente recursos ricos e sofisticados para inúmeros fins.  O Silvelight da microsoft, vem ganhando espaço  e tem evoluido muito ultimamente. E isto, para fazer frente a tecnologias concorrentes como flash e o flex.  E como amamos arquitetura, onde ela se encaixa em um cenário deste? E o desenvolvimento em camadas? São perguntas que iremos responder neste post.

Cenário Tradicionar X Cenário RIA

     O que temos no cenário tradicional, é um cenário em que o número de requisições ao servidor é grande. A cada ação do usuário seja uma pesquisa, alteração ou inserção de dados, é realizada uma interação com o servidor. Este fluxo continuo, de requisição e resposta é inerente a este tio de cenário, pois o mesmo está preparadao para isto. Já no cenário RIA, o fato de expor recursos ricos, avançados e uma interface além de rica funcional como uma interface de um programa desktop, nos leva a ter que tomar determinados cuidados como evitar o excesso de requisições ao servidor para evitar um gargalo e perda de performance. São cuidados como este, que temos que ter na hora de montar uma arquitetura, para um sistema que roda em um cenário RIA.

RIA e os seus desáfios

     Um problema comum ao se desenvolver aplicações RIA e até mesmo um dos seus desáfios era justamente desenvolver em camadas. Observer a imagen abaixo:

( clique na imagen para visualizar no tamanho original )

     A imagen acima, ilustra um cenário web tradicional. Em que tanto a lógica da apresentação, como a lógica da aplicação ficam no servidor, sendo de responsabilidade da lógica da apresentação renderizar o resultado requisitado pelo cliente, que é quem interage com a mesma através de inúmeras requisições, cujas quais, devem ser evitadas em um cenário RIA. Observer a próxima figura:

( clique na imagen para visualizar no tamanho original )

    Na figura acima, observamos o que diferencia um cenário RIA de um cenário tradicional, e vemos que a lógica da apresentação, não está mais do lado do servidor junto com a lógica da aplicação, e sim do lado cliente. E isto se deve, ao fato de garantir a performance e evitar gargalos no sistema. Esta inversão é feita justamnete para manter o ambiente estável e evitar sérios problemas.

O WCF RIA Services

     O WCF RIA Services, é um middware de comunicação, ou seja, ele irá fazer a ponte entre a lógica da aplicação( no lado do servidor ) e a lógica da apresentação( no lado cliente ). Agindo assim como uma fronteira de confiança, atravéz da qual, as camadas de apresentação e aplicação poderão se comunicar e trabalhar. 

     O WCF RIA Services, visa facilitar, ou seja, tornar mais suave o desenvolvimento em camadas para aplicações RIA. Para isto ele expõe serviços, operações e entidades para ser consumido no lado do cliente. Para entender melhor observe a figura abaixo:

( Clique na imagen para visualizar em tamanho original )

     A figura acima ilustra bem como o  WCF RIA Services funciona. No lado esquerdo está o browser  está a  lógica da apresentação e a fronteira de confiança, ou seja,  uma interface,  um proxy em que a lógica da aplicação é exportada atravéz deste contrato. E atráz, no servidor, ficam as nossas bases de dados, comunicação com outros serviços e até o domnínio da nossa aplicação.

Domain Services X Domain Context

 

     Os Domaisn Services, são coração do WCF RIA Services. É ele quem controla, a serialização de objetos para ambos os lados servidor e cliente. Só precisamos escrever nosso código uma única vez e o mesmo, fica disponivél para os dois projetos em nossa solução: o projeto servidor e Cliente.  O Domain Context, é com ele que o cliente trabalha, ou seja, ele é um espelho perfeito do Domain Service, que roda no lado do servidor. Analise a figura abaixo:

( Clique na image para visualizar no tamanho original )

     No projeto servidor, fica o Domais Service. Que contem as entidades, operações e serviços com os quais nossa aplicação trabalha. E no projeto cliente, em que se encontra asolução silverlight, fica o Domain Context, espelhando as oerações, serviços e entidades contidas no Domaisn Service. Para um entendimento maior, vamo analisar o projeto HRApp disponivel no codeplex para download aqui:

( Clique na imagen para visualizar em tamanho original )

     Em uma mesma solução, estão os projetos servidor( ASP.NET  ) e client( Silverlight ). Veja abaixo, a descriçaõ deste projeto de exemplo.

Seta Azul: Indica o projeto silvelight, que é o projeto client. 

Seta amarela: Indica o projeto ASP.NET, que é o projeto servidor.

Seta Vermelha: Indica o arquivo que é gerado automaticcamente, pelo WCF RIA Services. Este arquivo, é gerado da exportação das funcionalidades do EDMX, que é o modelo de dados e as funcionalidades que podem ser adicionadas. Ou seja ele é o resultado da exportação do Domain Service, uma vez sendo compilada a solução se você abrir a pasta GeneratedCode destro da mesma, estará um arquivo deste( extesnão .g.cs ).

Seta Verde: Indica um EDMX, arquivo do entity Framework, que contém o modelo de entidades, que também tem suas funcionalidades exportadas para o arquivo que é gerado pelo WCF RIA Services.

     Entendendo melhor o processo, é que quando você compila o projeto, é feita uma cópia para o projeto silverlight, do seu Domain Service, ou jsea, automaticamente o mesmo é espelhado no Domaind Context. Que contem absolutament e tudo, que existe no Domain Service, operações e tnidades.  Olhe um trecho do código do Domain Service e do Domain Context.

Domain Service

( Clique na imagen para visualizar em tamanho original )

Domain Context

( Clique na imagen para visualizar em tamanho original )

     As figuras acima mostram, justamente o que foi dito. O Domain Context reflete justamente o Domain Services. E ai então pode-se trabalhar utilizando esta classe de proxy e navegar, chamar e utilizar todas funções e serviços disponívels no Domaisn Services. Bom Pessoal, espero ter ajudado e passar um pouco do WCF RAI Services e, e como ele pode ser extremamente útil no desenvolvimento em camadas, para aplicações RIA. Desculpem ter ficado tanto tempo sem blogar, mais procurarei estar compartilhando frequentemente, conhecimento. Abraços e até a próxima.

     Beleza, pessoal?

    No último post falamos sobre a injeção de dependência, e como ela atua como uma das formas de inversão de controle e como utilizar estes conceitos. O Unity é um framework de injeção de dependência lançado em 2008 pela Microsoft, o Unity nasceu com o propósito de nos auxiliar no desacoplamento de classes, manter uma  arquitetura mais “plugável”,  e além destes benefícios,  ele facilita a criação de testes unitários, por deixar as camadas mais desacopladas .

     O Unity é parte da Enteprise Library, mas pode também ser utilizado sem ela. Ele é um container de injeção de dependência, que tem a responsabilidade de resolver as dependências em uma hierarquia de classe, ou seja, ele vai verificar as dependências e construir os objetos baseado nas mesmas. O Unity também pode ser usado para interceptação, no caso de quem trabalha no estilo AOP. Ele pode resolver uma cadeia de dependências inteira como também resolver as dependências de objetos que não foram construidos por ele. Observe a figura abaixo:

( clique na figura para ampliar )

     A figura acima mostra o processo de injeção de dependência que o unity pode fazer. Ele trabalha com três tipos de injeção: injeção por construtor ( constructor injection), injeção por propriedade ( setter injection) e embora ele trabalhe com injeção por chamada de método, ele não dá suporte à interface injection, que Martin Fowler falava em seu artigo sobre inversão de controle e DI. Vejamos a descrição de como o Unity trabalha com cada uma delas:

Injeção por construtor (constructor injection ): Este tipo de injeção ocorre automaticamente. Quando você cria um objeto utilizando um container do Unity, ele gera instâncias para cada um dos parâmetros especificados na assinatura do construtor, registrando e mapeando a classe de cada objeto no container.

Injeção por propriedade (Setter Injection ): Este tipo de injeção é opcional. Você pode adicionar o atributo Dependecy para cada uma das propriedades que você deseja que o Unity resolva através do container. Exemplo:

public class BancoDadosWrapper
{
    [ Dependency ]
    public ILog Log
    { get; set; }
}

Injeção po chamada de método: Este tipo de injeção também é opcional. Você pode adicionar o atributo InjectionMethod  para cada um dos métodos que deseja que o Unity venha resolver através do container. O Unity verificará os parâmetros do método e retornará uma instância da classe que resolve o tipo de cada um dos parâmetros. Ele é úti, quando queremos ter métodos de inicialização para um objeto específico. Exemplo:

public class BancoDados
{
    private ILog __fobjLog;
 
    [ InjectionMethod ]
    public void Inicializar( ILog pobjLog )
    {
        this.__fobjLog = pobjLog;
    }

     Talvez, você pode estar se perguntando: como o Unity sabe qual classe implementa determinada interface? Como ele acha a classe que herda de uma determinada classe abstrata?  É justamente aí que entra a configuração no Unity.

Configuração

     O Unity  precisa ser configurado,  e há até aqueles que acham que isto é um ponto negativo para ele. A necessidade da configuração se dá porque você precisa mapear as abstrações ( interfaces ou classes abstratas) para suas implementações, ou seja, suas classes concretas, para que o unity possa resolver a dependência quando a mesma for solicitada. A confguração pode se feita por arquivo de configuração (web.config, por exemplo ), ou em runtime via código, programaticamente. Segue abaixo um exemplo de cada tipo de configuração:

Via arquivo web.config,

É necesário adicionar a section abaixo e configurar o container:

<configSections>
 <section 
type="Microsoft.Practices.Unity.Configuration.UnityConfigurationSection,
     Microsoft.Practices.Unity.Configuration"/>
</configSections>
 
 
Configuração do container
 
 
<containers>

  <container>
 
    <types>
 
      <type type="ILog" mapTo="LogBancoDados" />
 
    </types>
 
  </container>
 
</containers>

 

Programaticamente, a configuração é realizada utilizando-se o método RegisterType da classe UnityContainer.

var  objContainer = new UnityContainer();

objContainer.RegisterType< ILog, LogBancoDados>();

    Uma vez configurado, é muito fácil utilizar o Unity. Quando você quiser um objeto que implementa uma determinada abstração, é só chamar o método Resolve da classe UnityContainer.

 

var  objContainer = new UnityContainer();

var objLogger = objContainer.Resolve<ILog>();

     Vejamos agora um exemplo em que o Unity funciona como container de DI em uma classe que implementa um pattern de arquitetura, chamado Registry.  Observe a classe abaixo:

public class Registry
{
    private           IUnityContainer __fobjContainerDI;
    protected static Registry         __fobjinstancia;
 
    public Registry()
    {
    }
 
    public Registry(bool configurar)
    {
        this.__fobjContainerDI = new UnityContainer();
        this.__fobjContainerDI.RegisterType<ILog, LogBancoDados>();
        this.__fobjContainerDI.RegisterType<IGerenciaExcecao, GerenciaExcecao>();
    }
 
    protected static Registry Instancia
    {
        get
        {
            if (_instancia == null)
                _instancia = new Registry(true);
            return _instancia;
        }
    }
 
    public static ILog getLog()
    {
        return this.__fobjContainerDI.Resolve<ILog>();
    }

    public static IGerenciaExcecao getGerenciadorExcecao()
    {
        return this.__fobjContainerDI.Resolve< IGerenciaExcecao >();
    }
}

     No caso da classe mostrada acima, no construtor da mesma instanciamos um container do Unity. Após termos feito isto, registramos uma implementação para a interface Ilog e outra para a interface IGerenciaExcecao. Quando for utilizado o método  getLog ou getGerenciadorExcecao,  o container do Unity retornará para a classe que chamar o método um objeto da classe que implementa a interface Ilog ou IGerenciaExcecao, mostrando assim como se inverte o controle, ou seja, ao invés de depender de uma classe concreta, esta dependência passa a estar na direção oposta, apontando para uma abstração.  

     Pessoal, espero tê-los ajudado, de alguma maneira, a entender como utilizar o conceito de injeção de dependência e o Unity Application Block. O Unity é um framework fácil de usar, configurar e atende muito bem quando se quer utilizar IoC ( Inversion of Control ) em um projeto, obtendo uma arquitetura mais limpa e desacoplada. Até a próxima, com mais conteúdo  sobre arquitetura e afins.

 Abraços. 

                Em um post recente neste blog, falei sobre a inversão de controle ou inversão de dependência, que é uma técnica utilizada para diminuir o acoplamento entre classes.  Abordamos como o alto acoplamento pode prejudicar o design de uma arquitetura, tornar a sua manutenção custosa e até mesmo dificultar a sua evolução.  

               Hoje irei falar sobre um pattern chamado Injeção de Dependência, que é na verdade uma das formas de se fazer a inversão de controle e assim, garantir um baixo acoplamento em uma cadeia de classes.

                Antes de nos aprofundarmos no padrão, temos que entender que quando falamos em “injetar” uma dependência, a grosso modo, nada mais é do que passar uma classe  que será utilizada para uma classe que irá consumi-la.

                O padrão de injeção de dependência trabalha baseado em abstrações, sejam elas classes abstratas ou interfaces.  Se pudéssemos citar um “lema”, este seria: programe para uma interface e nunca para uma implementação.  E este “lema” realmente faz diferença quando queremos diminuir o acoplamento entre as classes do nosso modelo. Podemos trabalhar com a injeção de dependência de três formas: injeção por construtor (constructor injection); injeção por propriedade ou getters e setters no caso do Java ( setter injection ); e injeção por interface ( interface injection ). Observe o exemplo abaixo:

public class Artigo

{

    private Autor _objAutor;

    public Artigo( Autor pobjAutor )

    {

        this._objAutor = pobjAutor;

    }

}
     No exemplo acima,  a classe Autor é passada para a classe Artigo pelo construtor, mostrando claramente um exemplo de injeção via  construtor ( Constructor Injection ), mas o detalhe do exemplo acima é que embora tenhamos a injeção de dependência, não temos a inversão de controle, pois existe uma dependência da classe Artigo para a classe concreta de Autor , caracterizando um alto acoplamento.  E como não é este o cenário que desejamos,  iremos modificá-lo. Observe abaixo:

public class Artigo

{

    private IAutor _objAutor;

    public Artigo( IAutor pobjAutor )

    {

        this._objAutor = pobjAutor;

    }

}

     No exemplo acima, tendo sido feita a correção, já temos tanto a injeção de dependência quanto a inversão de controle. O objetivo deste exemplo é mostrar que podemos ter a injeção de dependência sem inversão de controle, mesmo que não seja o nosso cenário desejado, e até mesmo para que tenhamos cuidado na hora de colocar em prática o padrão.

     O padrão de injeção de dependência é baseado em outro padrão chamado Builder. O Builder será responsável por construir para nós os objetos e armazená-los em algum lugar. É aí que entra em ação o container, que é justamente o lugar onde os objetos construídos serão armazenados.  A definição mais simples para o container é que ele é um objeto que pode armazenar outros objetos dentro dele.

     Para ficar mais claro e até mais fácil de entender como funciona a injeção de dependência, observe o diagrama abaixo:

Dependency Injection

     O que o diagrama acima mostra é o seguinte:  está sendo passada a responsabilidade de criar um objeto para o builder, indicando a ele qual é a interface que nós desejamos. Ele cria o objeto que implementa a interface e injeta esta dependência na classe Cliente.

     E aí está a inversão de controle: ao invés da classe cliente saber qual classe concreta ela precisa utilizar, ela delega isto para outra classe que, além de retornar a implementação apropriada para aquela interface, ainda injeta a dependência. Com isto, quebramos o forte acoplamento e invertemos a dependência,  e ao invés de depender de uma classe concreta, passamos a depender de uma abstração,   passando a ter um cenário desacoplado, de fácil manutenção e evolução.

                Pessoal, espero tenham gostado do post e em breve estaremos falando sobre o Unity Application Block, que é um framework para se trabalhar com injeção de dependência. Com exemplos práticos, vamos colcoar a mão na massa e extrair o máximo possível deste padrão e ter uma arquitetura mais robusta e madura. Um forte abraço e até a próxima.               

Coesão e Acoplamento são princípios de engenharia de software muito utilizados. Quando queremos ter uma arquitetura madura e sustentável, temos que levar em conta estes dois princípios, pois cada um deles tem um propósito específico que visa melhorar o design do software. O que acontece é que muitas pessoas não sabem a diferença entre eles e acabam não conseguindo obter os benefícios que colocá-los em prática na hora de se desenhar a arquitetura de um software. 

                Coesão está, na verdade, ligado ao princípio da responsabilidade única, que foi introduzido por Robert C. Marin no inicio dos anos 2000 e diz que uma classe deve ter apenas uma única responsabilidade e realizá-la de maneira satisfatória. Ou seja, uma classe não deve assumir responsabilidades que não são suas e uma vez sendo ignorado este princípio, passamos a ter problemas, como dificuldades de manutenção e de reuso. Observe o exemplo abaixo:

public class Programa
{

    public void ExibirFormulario()    {
        //implementação
    }

    public void ObterProduto()    {
        //implementação
    } 

    public void gravarProdutoDB   {
        //implementação
    }
}

Como visto no exemplo acima, a classe Programa tem responsabilidades que não são suas, como obter um produto e gravá-lo no banco de dados. Então, dizemos que esta classe não está coesa, ou seja, ela tem responsabilidades demais, e o que é pior, responsabilidades que não são suas. Observe abaixo outro exemplo: 

public class Programa 

     public void MostrarFormulario()     { 
           //Implementação 
     } 

    public void BotaoGravarProduto( ) { 
        Produto.gravarProduto();
    } 

Vemos no exemplo acima, uma clara separação de responsabilidades, o que contribui para um design desacoplado e organizado. O formulário não assume o papel de cadastrar o produto, ele pede a quem tem a responsabilidade para que faça tal tarefa. O que temos que ter em mente é que uma classe deve ser responsável por exercer uma única responsabilidade e fazer outras classes cooperarem quando necessário. 

Já o acoplamento significa o quanto uma classe depende da outra para funcionar. E quanto maior for esta dependência entre ambas, dizemos que estas classes elas estão fortemente acopladas. O forte acoplamento também nos traz muitos problemas, problemas até semelhantes aos que um cenário pouco coeso nos traz. Observe o diagrama abaixo: 

Exemplo alto acoplamento

                Como podemos ver na cadeia de classes acima, o forte acoplamento na mesma torna muito custoso a sua manutenção e o seu gerenciamento, pois qualquer mudança vai afetar toda a cadeia de classes. A saida para cenários como este, é o que chamamos de Inversão de Controle que foi abordadado em um dado post aqui no blog. 

                Sabemos que no mundo “real” nem sempre podemos ter um cenário ideal, que é com um baixo acoplamento e coeso. Mas como arquitetos, temos que saber tomar a decisão correta, pois determinadas decisões não poderão ser revertidas, dependendo da fase em que estiver o projeto ou o tipo de decisão tomada. Ter classes com responsabilidades claras e um baixo acoplamento, embora não seja fácil de serem construídas,  nos traz benefícios como baixo impacto em uma possível manutenção, gerenciamento e manutenção facilitados. Também não podemos esquecer que as aplicações evoluem, mudam e, muitas das vezes, se transformam.  Se ignorarmos as melhores práticas na hora de desenhar uma arquitetura, poderemos ter sérios problemas. E para nos auxiliar, temos o princípio da responsabilidade única e a inversão de controle, cujo objetivo é obter-se um cenário de responsabilidades claras entre nossas classes  e um baixo acoplamento. Um forte abraço e até o próximo post.

Do dia 22 ao dia 25, foi realizado em porto alegre um evento muito importante na área de TI chamado Agile Brazil. Neste evento estiveram presentes personalidades importantes como Martin Fowler, Philippe Kruchten, Giovani Bassi entre outros. Nele foi falado sobre as metodologias ágeis de desenvolvimento de software, cujas quais nos últimos tempos tem sido largamente utilizados e sendo enxergada muito mais do que uma metodologia mais como uma cultura, ou seja, algo que pode fazer o cenário atual vivido na indústria de software mudar.

     Estas metodologias são baseadas no manifésto ágil, que é um documento que foi escrito por pessoas extremamente influentes no cenário mundial  de desenvolvimento de software e que tem servido de base para tool sets como  scrum e Extreme Programing que são os mais utilizados.Chega a ser até mesmo filosófico falar de metodlogias ágeis, por que existem momentos em que precisamos fazer uma profunda reflexão sobre os nossos processos e a maneira como estamos exercendo nossas funções e se algo está dando errado então é momento de parar e acertarmos. Atualmente temos problemas com entrega, escopo, prazo e segundo o chaos report nos últimos anos o percentual de projetos que falham é cada vez maior. E o Agiledg e os tool set´s baseados nele, é o fruto do esforço da comunidade mundial de desenvovlimento de software em mudar esta situação.

     Vale-se ressaltar, que , nem todos estão preparados para o Agile, e isto foi algo que inclusive em uma das várias palestras ministradas foi citado. Embora seja inegável  que passar a ser ágil é evoluir e ter um processo de desenvolvimento mais maduro, infelizmente nem todas as empresas por sua cultura ou até mesmo seu nivel de maturidade não estão preparadas para adotar o Agile, prova disto é que existe um índice alto de falha na adoção de metologias ágeis como por exemplo do Scrum, mais não é nada que vá nos fazer abaixar a cabeça ou nos dar por vencidos. Se hoje uma empresa quer passar a ser ágil e utilizar um dos tool set´s para implantar uma cultura ágil, a mesma, tem que estar disposta a realmente mudar e mudar nem sempre é fácil muita das vezes se encontra muitas pedras no caminho até chegar a um ponto desejado e isto é com esforço, muito trabalho e sacrifício.

   Foi um excente evento eu estive presente e o sentimento que tenho é que estamos caminhando a passos largos para uma revolução no mundo do software. O Agile vem crescendo bastante e a prova disto é os mais de 800 inscritos no evento e é isso ai vamos em frente e ainda que existam pedras pelo meio do caminho nós iremos explodi-lás, um Abraço e até o próximo post.

Follow

Get every new post delivered to your Inbox.