CarlosPisani.com

Blog sobre arquitetura de softwares
Untitled Page

       Este é mais um daqueles temas muito polemico, basta perguntar a um grupo de desenvolvedores se eles preferem utilizar ou não frameworks corporativos, a cada 10 com certeza 7 irão reprovar a ideia. Dos 3 que irão aprovar, 2 provavelmente nunca trabalhou com frameworks corporativos e 1 vai alegar ter tido uma boa experiência.

       Estes números são exatamente os mesmos dos Frameworks bem sucedidos, a cada 10 um e olhe lá, este post destina-se a ajudar arquitetos e desenvolvedores a criar Frameworks corporativos bem sucedidos.

       Para quem não gosta de Frameworks, eu digo, acredite, existem bons Frameworks e quando bem pensados, projetados, elaborados, construído e mantidos eles ajudam muito.

       A prova disso é que trabalhamos com vários frameworks produzidos por grandes companhias como, por exemplo, .net, WCF, WPF, EF por ai a fora.

       O primeiro passo para construir o seu framework é ter um bom motivador, esta etapa é a mais importante para se ter êxito, se a sua motivação é criar um Framework para colocar no seu curriculum, para deixar tudo padronizado, ou ainda para forçar os desenvolvedores a fazer as coisas como você determina, esqueça, seu projeto não vai dar certo, você não conseguira agradar o seu publico alvo, neste caso os desenvolvedores, e com eles insatisfeitos dificilmente o projeto ficara pronto no tempo e com boa qualidade. Os melhores motivadores são os embasados nas necessidades dos desenvolvedores e da equipe, por exemplo, a sua empresa tem inúmeras regras para mandar e-mails, e isso exige mais do que simplesmente criar um smtpMessage, ou seja, o corpo sempre precisa ter algum tipo de conteúdo e o envio precisa ser registrado para futuras consultas ou auditoria, então você observa que este procedimento é sempre assim e que em dois ou mais sistemas todas estas regras foram reescritas ou copiadas e coladas, bem neste caso é obvio que o mais inteligente é colocar estas regras em um tool-kit (uma dll totalmente desacoplada da sua aplicação que pode ser utilizada por qualquer outra), com isso você ganhara reuso daquele código e qualquer melhoria ou manutenção precisara ser feita somente em um lugar.

       Conforme o seu tool-kit ganhar força e funcionalidades, procure torna-lo modular, separando por namespaces e dlls os tipos de funcionalidades. Um tool-kit grande ou um conjunto de tool-kits, quando possuírem referencia funcional ou lógica entre si para atingir um objetivo sistêmico reutilizável é um Framework.

       É muito importante agrupar as funcionalidades do seu tool-kit ou framework de forma lógica e organizada, sem referencias circulares e sem nenhuma dependência sistêmica com qualquer software corporativo, lembre-se os sistemas devem utilizar o seu framework e nunca o contrário.

       Outro fator decisivo no sucesso do seu framework é dividi-lo em camadas, particularmente não gosto de muitas tiers (camadas físicas) e layers (camadas lógicas), procuro trabalhar com poucas divisões, principalmente para frameworks, gosto do velho e bom modelo em 3 camadas:

  • Interface: Interface sistêmica, não visual, aqui costumo aplicar muito os padrões façade e singleton, deixe somente os métodos desta camada públicos e os mantenham o mais sintetizados possível, lembre-se da regrinha básica do encapsulamento onde o seu usuário, neste caso os desenvolvedores, não precisam conhecer como o seu framework funciona para utilizá-lo, como no bom e velho exemplo dos telefones, você só precisa saber operá-lo ou seja, esperar o sinal digitar os números esperar alguém atender e falar, não é necessário entender de telefonia ou conhecer os componentes internos do equipamento, basta usar a interface simplificada do telefone e toda a mágica acontece, faça a mesma coisa pelos seus desenvolvedores e o seu framework será bem sucedido. Uma dica adicional, procure implementar nesta layer somente chamadas as demais camadas, imagine por exemplo que para obter um determinado resultado é necessário fazer duas ou mais chamadas sequencialmente a camada de negócios, faça isso em um dos seus métodos desta camada, coloque nela também tratamento de erros e comentários no cabeçalho de cada método, facilitando o seu uso (via intelisence, os devs agradecem).

  • Negócios: Nesta camada procure desenvolver toda a inteligência da funcionalidade, abuse de padrões de projeto (obviamente para solucionar problemas conhecidos não para enfeitar) e faça todas as chamadas necessárias a sua camada de persistência. Nesta camada os métodos devem ser privados, protegidos ou internal, deixe internal somente os métodos que poderão ser utilizados pela sua camada front (Interface).

  • Dados: Obviamente esta camada é a menos inteligente, deixe somente regras de persistência aqui, seja ela na memória, no banco ou até mesmo em arquivos. Particularmente quase não aplico padrões de projetos aqui, no máximo flyweight.

       Dada a visão de motivador e de estrutura de um framework, vou relatar um uso recente desta prática no meu dia a dia, atualmente estou implementando a segunda versão de um framework na empresa onde trabalho nele agrupei uma série de funcionalidades como Segurança, Log, Helpers (de conexão com banco, configurações de email etc), Mensagens, SLA entre outros, os sistemas estão pouco a pouco começando a utilizar as suas funcionalidades, nada esta sendo refeito, mas sempre que algo novo é desenvolvido, já avaliamos se o framework não consegue ajudar a construir mais rápido ou de maneira onde a qualidade seja maior, se a funcionalidade não existe no framework e poderá futuramente ser utilizada por outros sistemas, avaliamos a possibilidade de incorpora-la ao framework, sempre sem impactar no desenvolvimento, mesmo que o código seja criado dentro da aplicação e posteriormente migrado para o framework.

       Uma boa pratica que estou utilizando e que recomendo ao extremo, é que na evolução do seu framework você sempre tome muito cuidado para manter a compatibilidade dos recursos existentes, lembre-se ao alterar a assinatura de qualquer método da sua camada de Interface, ao menos que sejam novos parâmetros e opcionais, o ajuste exigira um refactoring de todos os softwares que utilizam o seu framework, podendo gerar inúmeros desconfortos e abalar a confiança da equipe e da empresa no seu trabalho, as evoluções são importantes, mas sempre pense nos seus usuários e sempre trabalhe para manter a compatibilidade do seu framework. Só para reforçar, vou voltar ao exemplo dos telefones, dês de a sua criação, eles mudaram muito, muito mesmo, temos até celulares, mas você consegue operar um modelo de 50 anos atrás com a mesma facilidade de um aparelho moderno, isso por que a interface foi mantida, mesmo com todo o avanço tecnológico que ocorreu por dentro dos equipamentos, faça o mesmo com o seu framework, esta é uma receitinha de bolo que nunca falha.

       Minha dica final sobre o tema é: Não tenha pressa, lembre-se de que a pressa é inimiga da perfeição, agrupe funcionalidades pouco a pouco, crie tool-kits, deixe com que eles sejam usados e com o seu amadurecimento, baseando-se sempre nas necessidades da sua equipe, evolua ele para um framework, torne o seu tool-kit ou framework opcional e flexível, ele deve ajudar os desenvolvedores no dia a dia e não tornar as coisas mais complicadas.

Um grande abraço.

 

Ajude a melhorar este post

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



Untitled Page

Padrões estruturais - Proxy

       Um padrão pouco utilizado diretamente mas muito utilizado indiretamente.  Proxys são sistematicamente utilizados em serviços WCF's e também na iteraperobilidade entre recursos gerenciados e não gerenciados, interface com o COM+ por exemplo.

     Mas você sabe para que serve um proxy? Bem vou dar o exemplo do livro "Padrões de projeto" (um dos meus favoritos), Imagine que você va elaborar um programa que leia e escreva documentos ricos rtf ou docs por exemplo, abrir um arquivo repleto de imagens e carregar todas as imagens logo na abertura do documento poderia levar vários minutos, entediando os usuários, o ideal é carregar as imagens por demanda, mas oque colocariamos no lugar das imagens, um proxy é a resposta, ele servirá de interface (muito mais leve e rápido de carregar doque a imagem), e no momento em que o proxy é exibido (acessado) a imagem é carregada em memoria. O seu uso como interface WCF, COM+ ou outros é exatamente o mesmo, ao invés de instanciar o  objeto em memoria na inicialização do programa é inicializado somente o proxy aumentando a performance da aplicação, isso ajuda também na construção e no reuso de conexões em pool.

Quando utilizar

 Utilize este padrão quando:

  • Quando for necessário utilizar uma referência mais rica e versatil a um objeto ao invés de uma simples referência ou ponteiro;

  • Quando se desejar postergar o carregamento de objetos em memória;

Estrutura do padrão

Onde:

  • Proxy: Mantém uma referência que permite ao proxy acessar o objeto real. O proxy pode referenciar um subject se as interfaces de RealSubject e Subject forem as mesmas; Fornece interface idêntica a de Subject, de modo que o proxy possa substituir o objeto real; Controla o acesso ao objeto real e pode ser responsável pela sua utilização.

  • Subject: Define uma interface comum para RealSubject e Proxy, de maneira que um Proxy possa ser usado em qualquer lugar em que um RealSubject é esperado;

  • RealSubject: Define o ojeto real que o proxy representa;

Exemplo

        Abaixo um exemplo em C# do uso do padrão, nele postergamos a validação do usuário para o momento oportuno, note que até este momento o objeto que possue todas as referencias de validação de usuário não é carregado, se considerarmos que o objeto real é pesado e que pode levar varios segundos para ser carregado, não é interessante que ele seja criado na inicialização do programa.

Ajude a melhorar este post

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



Untitled Page

Devemos utilizar Stored Procedures ou ORMs?

Neste post gostaria de expressar minha opinião sobre este tão polemico tema, que leva muitos desenvolvedores a se desentenderem, questionarem e posteriormente criticar os inúmeros problemas de projetos ocorridos.

Bem em primeiro lugar, não digo que não existe, mas um projeto sem problemas é muito difícil de ver, eu mesmo, em mais de 15 anos, não me lembro de ter participado de algum que a solução atendia 100% as expectativas de todos os envolvidos, muito menos da equipe, afinal neste ramo sempre tem alguém para criticar oque foi feito e como foi feito.

Tendo essa prerrogativa como base, o meu maior conselho é não se apegar nos seus anseios por utilizar a tecnologia mais nova ou pelo desejo de ter no currículo que trabalhou x tempo com a tecnologia z, se o projeto não for bem sucedido então você não terá motivos para se orgulhar de ter participado dele.

Assim como ORM’s, as procedures também funcionam bem e são sistematicamente utilizadas a décadas, ambas possuem vantagens e desvantagens, neste post abordaremos as principais, o importante é conhecer bem os pontos fortes e fracos do projeto, meu conselho, saiba responder as perguntas abaixo;

Você tem uma visão funcional do todo?
    - Caso negativo, aconselho que tente orbite-la antes de tudo, sem uma visão do todo, você terá muito mais problemas do que pode imaginar;
Você possui todos os requisitos não funcionais (como tempo de resposta, o ambiente em que o sistema irá rodar [banco, aplicação e maquina do cliente])?
    - Este trabalho é a base de qualquer trabalho de arquitetura, se você não faz, então com certeza esta caindo na primeira prerrogativa deste post, projetando uma solução baseada nos seus anseios profissionais (e talvez no da sua equipe), mas não esta se baseando nas reais necessidades do seu cliente e sendo 100% sincero, um arquiteto assim atrapalha mais do que ajuda;
    - Não se esqueça de definir aqui o seu modelo, baseado nas abstrações funcionais além de incluir uma ideia de volumetria de dados;
Você já tem uma equipe montada?
    - Se sim ela esta preparada para utilizar a tecnologia que você como arquiteto esta ajudando o seu cliente a escolher?
    - Se não qual é a dificuldade de achar alguém no mercado realmente qualificado para atuar?
Os custos valem a pena?
Treinamento de uma equipe seria uma opção viável?
Qual será o real ganho em empregar tal tecnologia
Tendo todas estas respostas, avalie bem as vantagens e desvantagens da tecnologia e faça uma escolha sabia, abaixo descrevo as principais:

Procedures/ADO
    - Vantagens:
         Performance ligeiramente superior, de 1 a 2 décimos de segundo, parece pouco mas considere como um ponto forte quando o seu modelo trabalhar com milhares de registros;
         Centralização das regras DML, este é um ponto bem relevante, se você tiver vários programas feitos em tecnologias diferentes, você terá um grande reuso de funcionalidades, evitando reescrever código em dezenas de sistema a cada alteração (seja em tabelas ou em regras relacionadas a Insert/Update/Delete ou Select;
         Alta disponibilidade e monitoramento, procedures ficam compiladas no banco, local onde as normalmente as empresas investem pesado com maquinas mais “parrudas”, redundantes e gerenciadas por um DBA;
    - Desvantagens:
         Demora mais para implementar, logo também custa mais caro;
         Pode comprometer a performance do banco, deve ser muito bem feito e revisado;
         Maior burocracia para publicação;

ORM’s
    - Vantagens:
         Velocidade no desenvolvimento, ponto muito importante a ser considerado, o custo do projeto será significantemente menor, sua camada de dados será entregue bem mais rápido;
         Flexibilidade para implementação em diversos tipos de solução como Webservice, Serivços WCF, Frameworks ou toolkits, além de poder fazer parte da própria solução, esta flexibilidade se estende a sua publicação pode estar em um servidor, em um farm de servidores além de muitas outras opções;
         Possibilidade de trabalhar com vários SGBD’s diferentes, com um código padronizado e em geral simples e facilmente compreendido pelos desenvolvedores, resumindo fácil de manter;
    - Desvantagens:
         Devido a uma grande variedade deste tipo de Framework (ORM’s), é difícil encontrar profissionais que conheçam a tecnologia escolhida a fundo;
         Maior consumo de recursos da maquina, ORM’s em geral utilizam no seu kernel um recurso da plataforma .Net chamado reflexão, este recurso possibilita uma “compilação dinâmica”, isso costuma custar caro para o processador e para a memória do servidor ou da estação cliente;
         Maior dificuldade para resolver problemas, devido a ser algo relativamente novo (pouco mais de 10 anos, no nosso mercado pegou mesmo quando a Microsoft lançou o LINQ), e devido a ser uma caixa preta (mesmo open source é raríssimo alguém abrir o fonte e tentar resolver algum problema) é bem complicado superar problemas, principalmente em situações atípicas, de qualquer forma é raro este tipo de ocorrência;

Tentei não ser repetitivo nas vantagens e desvantagens, em geral os itens listados como vantagens de uma escolha são desvantagens da outra, gostaria de encerrar este post dizendo que existem muitas outras vantagens e desvantagens de qualquer escolha que você faça como arquiteto, o melhor conselho que posso dar é, mantenha a sua mente aberta, não se prenda a antigos conceitos e paradigmas, mas também não deixe de considera-los, inove mas foque nas necessidades do seu cliente.

Um grande abraço.

Ajude a melhorar este postt

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



Untitled Page

Design Patterns

Padrões estruturais - Flyweight

       Dando continuidade a serie de posts sobre design patterns, falaremos hoje sobre o padrão Flyweight, padrão que particularmente gosto muito e utilizo no meu dia a dia, o mais interessante foi que durante a minha graduação um dos meus professores foi enfático ao dizer que este é um padrão em desuso, devido  ao seu foco principal ser economia e reuso de memória, e devido a memória nos dias atuais ser algo barato facilmente expansível. O fato é aplicações web costumam consumir muita memória e dependendo da arquitetura adotada (ou da falta de uma definição arquitetural), inúmeras variáveis de sessões são utilizadas e muitas vezes cache são utilizados inclusive de forma incorreta.

       Este padrão, como dito anteriormente, tem como objetivo principal o reuso de memória através da criação de recursos estáticos e de uma inteligência para retornar uma referencia a um recurso ja alocado quando necessário, assim você cria e aloca uma única vez um valor em memória e o reutiliza cada vez que se desejar o mesmo recurso, pense em um editor de textos, se cada caractere formatado for uma classe imagine quanta memória seria necessária para alocar um livro inteiro, em um caso como este o uso do padrão poderia ser aplicado duas vezes uma para representar os caracteres e outra para representar as formatações, depois aplicando o padrão decorator você pode utilizar a formatação de um flyweight em uma referencia de caractere do flyweitght de caracteres, utilizando muito pouca memória. 

Quando utilizar

 Utilize este padrão quando:

  • Uma aplicação utiliza um grande número de objetos em memória;

  • O custo de armazenamento dos objetos são altos devido a grande quantidade de objetos alocados;

  • Muitos grupos de objetos podem ser substituídos por relativamente poucos objetos compartilhados, uma vez que estados extrinsecos são removidos;

  • A aplicação não depende da identidade dos objetos, uma vez que objetos flyweight podem ser compartilhados e testes de identidade produzirão o valor verdadeiro para objetos conceitualmente distintos.

Estrutura do padrão

Onde:

  • Flyweight: declara uma interface através da qual flyweights podem receber e atuar sobre estados extrínsecos;

  • ConcreteFlyweight: Implementa a interface flyweight e acrescenta armazenamento para estados intrísecos, se houver. Um objeto Concrete flyweight deve ser compartilhável e qualquer estado que ele armazene deve ser intrínseco, ou seja, independente do contexto do objeto ConcreteFlyweight (ou comum para todas as suas referências);

  • UnsharedConcreteFlyweight: Nem todas as subclasses de flyweight necessitam ser compartilhadas. A interface de flyweight habilidatada o compartilhamento, ela não o força ou o garante. É comum para objetos UnsharedConcreteFlyweight não compartilhar objetos concreteflyweight como filhos sem algum nível da estrutura de objetos de flyweight;

  • FlyweightFactory: Cria e gerencia objetos flyweight e garante que os objetos flyweight sejam compartilhados de maneira apropriada;

  • Client: mantém uma referência para flyweights e computa ou armazena o esta extrínseco de flyweights;

Uso do padrão na prática

        Como sugestão de uso do padrão, você pode aplica-lo para criar o modulo de autenticação de usuários em uma aplicação web, persistindo em objetos flyweight as roles de cada usuário. Sessions devem ser utilizadas com moderação entretanto uma variável deste tipo por usuário para garantir as suas permissões enquanto utiliza o sistema, fazendo referencia a um flyweight de role será extremamente leve e rápido (pois esta em memória). Esta também é uma decisão inteligente pois roles são comuns para inúmeros usuários, não é necessário buscar no banco a cada acesso, nem muito menos armazenar as permissões de cada usuário de forma independente, afinal é por isso que exitem roles.

       O padrão pode ser utilizado em muitos outros casos, no post anterior falei sobre um workflow que projetei, para monta-lo estou utilizando o padrão flyweight também, uma vez que existem dois ou três templates e todo o resto são informações sobre o seu processo, com o padrão retorno o template do workflow montado, o clono, e busco no banco somente o estado atual do workflow especifico, com isso reduzi o tempo de resposta de 3 segundos para 2 décimos de segundo.

       Parece ótimo usar este padrão para muitas coisas, não é verdade, bem eu realmente gosto muito dele, mas ha desvantagens, uma a ser considerada, a manutenção de dados relacionados ao estado comum dos objetos flyweight precisam passar pela factory antes de ser persisitidos na base, caso contrário, você corre o risco de atualizar os dados na base e na prática a informação levar horas ou atém mesmo dias ou semanas para serem refletidas no sistema, afinal o flyweight em questão pode estar em memória e podem não ser atualizados tão cedo (pense nisso antes de utilizar o padrão).  

Exemplo

        Abaixo um simples exemplo do uso do padrão flyweight, em sistemas web é uma escolha bem interessante quando falamos em reuso de memória, hoje em dia temos varias formas de economizar I/O e deixar as páginas mais rápidas, como o uso de cache por exemplo, de qualquer forma, este padrão não tem nada haver com cache de conteúdo estático, muito pelo contrário, recentemente eu  o utilizei para construir um Workflow muito complexo, cada nova proposta iria possuir mais de 5 workflows, totalizando mais de 1200 registros, um problema adicional é que esta será a tela mais utilizada do sistema, montar este monstro para cada proposta seria loucura, um desperdício de memória e processamento, com o padrão criei um protótipo em memória no primeiro uso do primeiro usuário da árvore completa (utilizei o padrão composite para criar a estrutura do flow), fazendo somente um get na base de dados da estrutura do workflow, para todos os outros utilizo uma referencia do workflow em memória aplicando somente as ações dos usuários da proposta especifica. O nosso exemplo é bem mais simples para facilitar o entendimento, nele subimos uma única vez as roles de um usuário em memória, caso outro usuário possua a mesma role, ao utilizar o factory do padrão ela será retornada da memória e não será construida com base em dados do banco.

using System;

using System.Collections.Generic;

 

namespace FlyweightSample

{

 

    /// <summary>

    /// EN: Uses the pattern flyweight to

    /// extreme reuse virtual memory, this sample

    /// shows how to use this patterns with the

    /// most comom situation, how to load the

    /// users permissions reusing when the same

    /// roles are used for many users.

    ///

    /// PT: Utilize o padrão flyweight para

    /// um reuso extremo de memoria virtual

    /// este exemplo mostra como utilizar este

    /// padrão em uma das mais comuns situações,

    /// como carregar as permissões dos usuários

    /// reusando-as quando as mesmas forem utilizadas

    /// por varios usuários.

    /// </summary>

    public class SaleSample    

    internal class Program

    {

        private static void Main(string[] args)

        {

            //EN: Here we just get permissions,

            //many users will use this routine

            //everyday

 

 

            //PT: Aqui fazemos simplesmente fazendo

            //um get das permissões, varios usuários

            //passaram por esta rotina diariamente

 

            FlyweightRoleFactory factory = new FlyweightRoleFactory();

            FlyweightRole myRole = factory.GetRole(1);

        }

    }

 

    /// <summary>

    /// EN: Here we create the roles abstraction that

    /// can be used for a lot of systems

    ///

    /// PT: Aqui criamos a abstração de roles que pode ser

    /// utilizado por varios sitemas

    /// </summary>

    public abstract class FlyweightRole

    {

        public int RoleId { get; set; }

        public string RoleName { get; set; }

        public abstract int PermissionLevel { get; set; }

    }

 

    public class SystemARole : FlyweightRole

    {

        public int minLevel = 1;

        public int maxLevel = 5;

        public int permissionLevel = 1;

 

        public override int PermissionLevel

        {

            get { return permissionLevel; }

            set

            {

                if (value < minLevel)

                {

                    throw new Exception("Min value for this property is "

                        + minLevel.ToString());

                }

 

                if (value > maxLevel)

                {

                     throw new Exception("Max value for this property is "

                        + maxLevel.ToString());

                }

 

                permissionLevel = value;

            }

        }

    }

 

    public class SystemBRole : FlyweightRole

    {

        public int minLevel = 0;

        public int maxLevel = 8;

        public int permissionLevel = 0;

 

        public override int PermissionLevel

        {

            get { return permissionLevel; }

            set

            {

                if (value < minLevel)

                {

                    throw new Exception("Min value for this property is "

                        + minLevel.ToString());

                }

 

                if (value > maxLevel)

                {

                     throw new Exception("Max value for this property is "

                        + maxLevel.ToString());

                }

 

                permissionLevel = value;

            }

        }

    }

   

    /// <summary>

    /// EN: Here the trick happens, we create the roles only if it

    /// doesn't exists on virtual memory, if exists, we just return

    /// the role reference, this class works with Web systems, for

    /// client-server systems, you should create a shared dll or

    /// WCF Service.

    ///

    /// PT: Aqui o truque acontece, criamos as roles somente se elas não

    /// existirem na memória, caso contrario retornamos uma referencia

    /// sua, esta classe funcionaria legal em um sistema web, em um

    /// sistema client-server, para termos o mesmo efeito, precisariamos

    /// coloca-la em uma dll compartilhada por varios sistemas, ou

    /// simplesmente criar um serviço WCF.

    /// </summary>

    public class FlyweightRoleFactory

    {

        private Dictionary<int, FlyweightRole> loadedRoles =

            new Dictionary<int, FlyweightRole>();

 

        public FlyweightRole GetRole(int roleId)

        {

            if (loadedRoles.ContainsKey(roleId))

            {

                return loadedRoles[roleId];

            }

 

            switch (roleId)

            {

                case 0:

                    {

                        loadedRoles.Add(0,FakeDataBase.GetAdmRoleA());

                        break;

                    }

                case 1:

                    {

                        loadedRoles.Add(0,FakeDataBase.GetPublicRoleA()); 

                        break;

                    }

                 case 2:

                    {

                        loadedRoles.Add(2,FakeDataBase.GetAdmRoleB());

                        break;

                    }

                case 3:

                    {

                        loadedRoles.Add(3,FakeDataBase.GetPublicRoleB()); 

                        break;

                    }

                default:

                    {

                        throw new Exception("Invalid RoleId.");

                    }

            }

               

            return loadedRoles[roleId];

        }

    }

 

    public class FakeDataBase

    {

        public static FlyweightRole GetAdmRoleA() {

            return new SystemARole()

                       {

                           RoleId = 0,

                           RoleName = "Administrator",

                           PermissionLevel = 5

                       };

        }

 

        public static FlyweightRole GetPublicRoleA() {

            return new SystemARole()

                       {

                           RoleId = 1,

                           RoleName = "Public",

                           PermissionLevel = 1

                       };

        }

 

        public static FlyweightRole GetAdmRoleB() {

            return new SystemARole()

                       {

                           RoleId = 2,

                           RoleName = "Administrator",

                           PermissionLevel = 8

                       };

        }

 

        public static FlyweightRole GetPublicRoleB() {

            return new SystemARole()

                       {

                           RoleId = 3,

                           RoleName = "Public",

                           PermissionLevel = 0

                       };

        }

    }

}

 

 

Ajude a melhorar este post

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



Untitled Page

Sugestão de uso de design patterns

        Muitos tem me pedido para fugir um pouco da rotina e falar um pouco mais sobre como utilizo design patterns, atendendo a estes pedidos escreverei também sobre isso, e vou fazer o possível para falar somente dos padrões que já abordamos. Estes posts serão mais curtos não entraremos nos detalhes dos padrões, vou me preocupar mais em passar o problema e como o padrão o solucionou.

       Nestas ulltimas duas semanas enfrentei um grande desafio profissional, precisava fazer rapidamente um Workflow, o modelo que existia contava com mais de 20 tabelas e ia precisar triplicar o seu tamanho para atender as necessidades do cliente. Após algumas horas de estudo do modelo e entendendo as necessidades de negocio, vislumbrei que o modelo de dados do workflow, que era basicamente formado por workflows, grupos, sub-grupos, ações e finalizadores de ações faziam parte de uma estrutura de árvore, e como ficaria legal uma telinha para mante-lo a lá Windows Explorer, seguindo a mesma ideia de pastas e subpastas, podendo ter ilimitados subníveis e com usabilidade de arrastar e soltar. Bem foi assim que eu pensei, utilizei o padrão composite, que é o mais apropriado para estruturas de árvore, corri para o EA e desenhei o modelo, dividi a solução em duas tiers uma para compor o motor e tornar simples o uso da árvore e outra para o front-end.

        Na tier do motor que chamo de kernel, apliquei o padrão composite para centralizar todas as funcionalidades de árvore do workflow, funcionalidades como adicionar um novo item, remover itens, consultar itens, regras de estados do workflow e converter a estrutura para entidades, isso facilita o seu uso em view state uma vez que minha entidade é livre de tecnologia, utilizo POCO e posso aplicar o atributo serializable nelas. Como manda o padrão muitas estruturas recursivas foram utilizadas, isso não necessáriamente o torna complexo, mas a forma como os metodos trabalham em conjunto é complexo por este motivo também utilizei o padrão façade, garantindo o baixo acoplamento entre as tiers, na classe onde apliquei o padrão façade, deixei publico somente 4 métodos, adicionar, excluir, consultar, e transformar em entidade, os demais eram métodos privados somente para reduzir a complexidade dos metodos públicos. Todas as classes do kernel são internal, com exceção as classes da camada de entidades e da camada façade.

       Na tier front-end, tive algumas preocupações atípicas, na minha empresa estamos passando por mudanças estruturais e tecnologicas na aplicação, sendo assim, e pensando no Workflow como um modulo isolado, coloquei ele em um web user control, utilizei um padrão de arquitetura que chamo de canvas behavior, onde isolo todo o conhecimento das regras da tela em uma camada agnóstica a tecnologia (falaremos deste padrão em breve), nesta camada são abstraidos todos os componentes da tela bem como todo e qualquer comportamento visual, tais como habilitar ou desabilitar um controle, exibi-lo ou não, etc...esta camada já faz a comunicação direta com a tier kernel, veja como ficou a solução arquitetural em uma visão macro:

 

 

  • Vantagens e desvantagens desta abordagem:

    • Vantagens:

      •  O MER ficou com apenas 9 tabelas novas (ao invés de +60);

      • Manutenção simples;

      • Possibilidade de fazer somente uma tela de manutenção, a ideia original girava em torno de 15;

      • Usabilidade superior: é muito melhor para o usuário arrastar e soltar do que ficar fazendo associações com dropdowns, além de uma visão em forma de mapa, isso ajuda muito o usuário;

      • Performance: Os componentes em memória ficaram pequenos, utilizei POCO isso foi bom tanto para o trafego dos dados como no consumo de memória, alem das estruturas recursivas que ajudam no processamento;

    • Desvantagens:

      • Não foi viável utilizar ORM: neste projeto estamos utilizando em quase tudo o Entity Framework 4, mas como MER acompanhou o modelo que projetei, precisei fazer inúmeras consultas para criação de um único Workflow, como cada workflow deve possuir mais de 100 itens, a performance, mesmo utilizando as melhores praticas do EF, em alguns casos até utilizando processamento paralelo ficou em 14 segundos, oque me forçou a utilizar o ADO puro mesmo, com isso o tempo de resposta caiu para 1 segundo. Sendo assim, foi bem mais trabalhoso criar a camada de dados, considero esta a única desvantagem da solução.

Ajude a melhorar este post

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



Untitled Page

Design Patterns

Padrões estruturais - Façade

       Em português também conhecido no mundo acadêmico como fachada, este padrão tem a intenção de fornecer uma interface unificada para um conjunto de interfaces em um subsistema.

       A principal ideia por tras do padrão é fornecer uma interface de nível mais alto tornando os subsistemas mais fáceis de serem entendidos e utilizados.

       Para abstrair e dar um melhor entendimento do padrão, vamos imaginar um telefone celular, ele possui inúmeros componentes com funcionalidades isoladas como o display, a campainha, o teclado e a bateria, todos essenciais para o funcionamento do aparelho, mas para utilizá-lo você precisa somente conhecer a interface básica ou seja o teclado, digite o numero do telefone e pressione a tecla verde, para fazer um telefonema e pressione a tecla vermelha para finalizar. Quero dizer que você não precisa ser um engenheiro eletrônico para operar um telefone celular, este padrão faz o mesmo pelas suas classes, tornando o seu entendimento mais facil principalmente para aquelas que trabalham em conjunto para um fim especifico.

       Considere o uso do padrão como o acabamento da sua layer, se ele for bem aplicado ajuda e muito no uso do terceiro grande conceito da orientação a objeto o Encapsulamento.

Quando utilizar

 Utilize este padrão quando:

  • Desejar-se fornecer uma interface simples para uma camada ou um subsistema complexo;

  • Existirem muitas dependências entre clientes e classes de implementação de uma abstração;

  • Desejar-se dividir ou estruturar um subsistema em camadas.

Estrutura do padrão

Onde:

  • Façade: Conhece as classes do subsistema responsáveis por atender uma solicitação, delega solicitações de clientes a objetos e fornece uma interface simples e sintetizada as clientes;

  • Classes de subsistema: Classes que compõe o subsistema e que trabalham em conjunto para a execução de uma ou mais ações sistêmicas que atendem uma ou mais regras de negócio ou requisitos (funcionais ou não funcionais).

Exemplo

        No exemplo abaixo ilustro o uso do padrão façade em uma das mais rotineiras situações do universo dos programadores, uma rotina de vendas, observe que no namespace façade ha inúmeras classes e regras (isso costuma ser ainda muito maior), observe também que todas estas classes estão encapsuladas através do modificador de acesso internal e que a única classe pública deste namespace é a classe sale, chave do nosso padrão, nela foi aplicado o pattern façade, unificando todo o conhecimento de como uma venda deve ser executada garantindo uma alta coesão e um baixo acoplamento.

       Já no namespace Sample, simplesmente utilizamos a nossa classe façade, observe o seu uso na classe saleSample, com apenas 5 linhas de comando uma venda com 3 mercadorias é realizada, não necessitando a classe cliente conhecer todo o funcionamento do mecanismo de venda.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Facade;
 
namespace Sample {
   
    /// <summary>
    /// EN: Uses the pattern façade to
    /// encapsulate the businees rules to
    /// make the code loosely coupled and
    /// self cohesive
    ///
    /// PT: Utilize o padrão Façade para
    /// encapsular as regras de negócio e
    /// manter o código com alta coesão e
    /// baixo acoplamento
    /// </summary>
    public class SaleSample {
        static void Main(string[] args) {
            Sale mySale = new Sale();
            mySale.AddGoods("Book",float.Parse("22.2"));
            mySale.AddGoods("DVD",float.Parse("4.0"));
            mySale.AddGoods("Mouse pad",float.Parse("30.10"));
            mySale.Finish(13);
        }
    }
}
 
namespace Facade
{
    public class Sale
    {
        private InvoiceEntity inv = null;
 
        public Sale()
        {
            if (inv==null)
            {
                inv = new InvoiceEntity()
                          {
                              Date = DateTime.Now,
                              Description = "New sale",
                              Number = DateTime.Now.Ticks
                          };
                inv.Details = new List<InvoiceDetailEntity>();
            }
        }
 
        public void AddGoods(string name, float price)
        {
            inv.Details.Add(new InvoiceDetailEntity(name,price));
        }
 
        public void Finish(int customerId)
        {
            BusinessValidate bv = new BusinessValidate();
            Delivery dv = new Delivery();
 
            if (bv.DoValidation(inv))
            {
                dv.Ship(customerId,inv);
            }
            else
            {
                throw new Exception("This sale cannot be finished.");
            }
        }
    }
   
    internal class Invoice
    {
        List<InvoiceEntity> invoices = new List<InvoiceEntity>();
 
        public void Add(InvoiceEntity invoice) {
            invoices.Add(invoice);
        }
    }
 
    internal class BusinessValidate
    {
        public bool DoValidation(InvoiceEntity inv)
        {
            //code that validates rules
            return true;
        }
    }
 
    internal class Delivery
    {
        public void Ship(int customerId, InvoiceEntity invoice)
        {
            //code that does the shipment
        }
    }
 
    internal class InvoiceEntity
    {
        public string Description { get; set; }
        public long Number { get; set; }
        public DateTime Date { get; set; }
        public List<InvoiceDetailEntity> Details{ get; set; }
    }
 
    internal class InvoiceDetailEntity
    {
        private static int id;
 
        public int Id { get; private set; }
 
        public string Description { get; private set; }
       
        public float Value { get; private set; }
 
        public  InvoiceDetailEntity(string descr, float value)
        {
            Id = id++;
            Description = descr;
            Value = value;
        }
    }
}
 
 

 

Ajude a melhorar este post

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



Untitled Page

Produtividade

Produtividade no desenvolvimento - ReSharper 5.0

        Atendendo ao pedido do amigo Renato Vilas Boas, hoje falaremos um pouco sobre o ReSharper 5.0, esta ferramenta foi uma dica do Renato e des de o primeiro momento em que utilizei notei os imensos benefícios que ele traz a produtividade.

       O ReSharper é uma extensão das ferramentas de produtividade impantada como um pugin para o Visual Studio (2005-2010) que o ajuda a melhorar a implementação usando C #, VB.NET, ASP.NET, XML, ou o código XAML. Ele detecta e remove os erros em código; acelera codificação, proporciona uma navegação rica e recursos de pesquisa, mais de 40 tipos de refactorings e muitas outras funcionalidades para os desenvolvedores. NET.

      Ele aumenta a produtividade em até 50%, não é um ferramenta mágica, requer que o profissional aprenda as teclas de atalho e evidentemente utilize a ferramenta de forma adequada. Um dos recursos mais fantásticos é a verificação de código, ele ajuda o desenvolvedor a corrigir problemas no momento em que ele está desenvolvendo, para produtividade é bem legal gerar massivamente propriedades com base em fields, basicamente selecionando os fields e mandando o ReSharper gerar as propriedades para você, muito legal mesmo. Bem tem muita coisa legal mesmo, como transformar um valor "chumbado" de uma string em um parâmetro de configuração com apenas 2 cliques, tornar o seu sistema multi-language se torna também uma missão fácil.

       Fica ai a minha recomendação, acesse o site http://www.jetbrains.com/resharper/ assista os vídeos, baixe a versão trial e teste a ferramenta eu garanto que você vai se surpreender com ela. Lembrando este blog não tem fins lucrativos, este post não é uma propaganda da ferramenta é apenas uma dica para ajudar os leitores.

Ajude a melhorar este post

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



Untitled Page

Design Patterns

Padrões estruturais - Decorator

       Este padrão tem a intenção de anexar responsabilidades adicionais a um objeto dinamicamente.

       Decoradores provêem uma alternativa flexível à herança para estender funcionalidades.

       Um bom exemplo de Decorator são o esquema de formatação de editores de texto, onde podemos considerar cada caractere do texto como um objeto, que pode ser decorado com cores, estilos e tamanhos distintos, seria extremamente inflexível colocar estes aspectos em propriedades de cada objeto, além do excessivo consumo de memória, aplicando o padrão any objeto podem receber estas características. Tool kits também utilizam frequentemente este padrão para possibilitar a extensão e customização de funcionalidades pré-existentes.

Quando utilizar

 Utilize este padrão quando:

  • Desejar-se acrescentar responsabilidades a objetos individuais de forma dinâmica e transparente, ou seja, sem afetar outros objetos;

  • For necessário adicionar responsabilidades a objetos que podem ser removidas;

Estrutura do padrão

Onde:

  • Component: Define a interface (a abstração) para os objetos que podem ter responsabilidades acrescentadas.

  • Concrete Component: Define o objeto que poderá receber responsabilidades adicionais.

  • Decorator: Representa a referência para um objeto Component e define uma interface que segue a interface de Component.

  • Concrete Decorator: Representa as responsabilidades acrescida ao componente.

Exemplo

        Nos exemplo abaixo utilizo o padrão decorator para agregar funcionalidades a empregados, por ai podemos verificar que padrões de projeto podem ser utilizados para vários fins, um uso comum de decorator é para a criação de mensagens, que recebem características diferentes se ela se tratar de um SMS, ou E-mail ou ainda um Post em uma rede social. Repare que nas classes concretas decorator é possível fazer um setEmployee de uma outra classe concreta de Decorator, agregando assim novas funcionalidades ao mesmo funcionário.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
 
namespace Decorator {
   
    /// <summary>
    /// EN: Uses the pattern Decorator to
    /// add features for employees
    ///
    /// PT: Utiliza o padrão Decorator para
    /// adicionar funcionalidades para
    /// empregados
    /// </summary>
    class Program {
        static void Main(string[] args)
        {
            Employee e1 = new Director()
                {Name="Joseph",
                Active=true,
                Age=32,
                ID=1,
                Salary=3000};
 
            Employee e2 = new Coordinator()
                {Name="Dayana",
                 Active=true,
                 Age=32,
                 DirectorId = 1,
                 ID=2,
                 Salary=3000};
           
            BuyProducts f1 = new BuyProducts();
            BuyProducts f2 = new BuyProducts();
            Approbation f3 = new Approbation();
 
            f1.SetEmployee(e2);
            f2.SetEmployee(e1);
            f3.SetEmployee(f2);
 
            f1.Buy("Paper");
            f3.ApproveBuy(1);
 
            f2.Buy("Notebook");
            f3.ApproveBuy(2);
 
            Console.Read();
        }
    }
 
    /// <summary>
    /// EN: Represents the employee abstraction
    /// on the pattern it is the "Component" Class
    ///
    /// PT: Representa a abstração de funcionário
    /// no padrão é a classe "Component"
    /// </summary>
    public abstract class Employee
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Age { get; set; }
        public decimal Salary { get; set; }
        public bool Active { get; set; }
    }
 
    /// <summary>
    /// EN: Represents the director
    /// on the pattern it is the "ConcreteComponent" Class
    ///
    /// PT: Representa o diretor
    /// no padrão é a classe "ConcreteComponent"
    /// </summary>
    public class Director:Employee
    {
        public string Sector{ get; set; }
    }
 
    /// <summary>
    /// EN: Represents the Coordinator
    /// on the pattern it is the "ConcreteComponent" Class
    ///
    /// PT: Representa o coordenador
    /// no padrão é a classe "ConcreteComponent"
    /// </summary>
    public class Coordinator:Employee
    {
        public int DirectorId { get; set; }
    }
 
    /// <summary>
    /// EN: On the pattern it is the "Decorator"
    /// abstraction
    ///
    /// PT: No padrão é a abstração de
    /// "Decorator"
    /// </summary>
    public abstract class FeatureDecorator:Employee
    {
        /// <summary>
        ///Function Description
        /// </summary>
        /// <returns></returns>
        public void SetEmployee(Employee concreteEmployee)
        {
            ID = concreteEmployee.ID;
            Name = concreteEmployee.Name;
            Age = concreteEmployee.Age;
            Salary = concreteEmployee.Salary;
            Active = concreteEmployee.Active;
        }
    }
 
    /// <summary>
    /// EN: On the pattern it is the
    /// "ConcreteDecoratorA"
    ///
    /// PT: No padrão é o
    /// "ConcreteDecoratorA"
    /// </summary>
    public class BuyProducts:FeatureDecorator
    {
        public int SolicitationId { get; set; }
 
         public void Buy(string productName) {
            Console.WriteLine("The employee {0} "+
                               "buys the product {1}",
                                Name,
                                productName);
        }
    }
 
    /// <summary>
    /// EN: On the pattern it is the
    /// "ConcreteDecoratorB"
    ///
    /// PT: No padrão é o
    /// "ConcreteDecoratorB"
    /// </summary>
    public class Approbation:FeatureDecorator
    {
        public void ApproveBuy(int solicitationNumber) {
            Console.WriteLine("The employee {0} approves " +
                              "the solicitation number: {1}",
                              Name,
                              solicitationNumber.ToString());
        }
     }
}

 

Ajude a melhorar este post

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



Untitled Page

Evento DNAD 2011

Amigos, neste post vamos falar um pouco sobre o maior evento sobre arquitetura de softwares Brasileiro, trata-se do DNAD.

A 3 anos este evento reúne profissionais de todo o país apresentando palestras extremamente relevantes e atuais, temas os quais julgo essenciais para qualquer arquiteto de software.

O evento é uma extensão do grupo de discussão Dot Net Architects, criado pelo MVP Giovanni Bassi, um dos melhores arquitetos de softwares do Brasil.

Ocorrerá em São Paulo em 3 e 4 de junho (sexta e sábado), o dia inteiro. Os palestrantes são figuras conhecidas do .NET Architects, do mercado e da comunidade em geral, contando com arquitetos, MVPs e desenvolvedores com experiência prática de mercado.

Para mais informações e inscrição acesse http://dnad.dotnetarchitects.net/dnad/2011/

"Eu vou...nos vemos lá..."

Ajude a melhorar este post

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



Untitled Page

Design Patterns

Padrões estruturais - Composite

Este post foi um dos mais pedidos pelo leitor Bruno Mendes, que gostou muito das explicações por e-mail, mas sempre me cobra de posta-lo no Blog. Para conhecimento de todos os leitores que me pedem por posts de padrões tenho seguido a ordem do catálogo de padrões do GOF, a ideia é cobrirmos todos os padrões deles, exatamente por serem os mais famosos e mundialmente utilizados, obviamente não irei parar por ai, na sequência seguirei para outros padrões utilizados em algum lugar do mundo e de eficácia comprovada para sistemas orientados a objeto.  

       Este padrão tem a intenção de compor facilmente estruturas robustas de árvore, tratando uniformemente suas partes ou toda a sua composição.

       Imagine um sistema que categorize seus produtos em uma hierarquia de árvore, como pastas (diretórios) de um sistema de arquivos, seria bem interessante poder mover um produto de uma categoria para outra ou uma pasta inteira com inúmeros produtos de uma categoria para outra, mas automaticamente teríamos um problema, teríamos que tratar de forma diferente mover um produto ou mover um grupo de produtos de um subgrupo para outro.

       O padrão Composite oferece uma solução viável para este problema, através de uma classe abstrata que padroniza o tratamento dos subitens , itens e nós, utilizando para este fim uma composição recursiva de elementos.

       Esta composição recursiva (classe Component no diagrama da sessão estrutura), é a chave do padrão composite, e precisa ser bem projetada para evitar grandes fatorações futuras, ao altera-lo, toda a árvore será impactada.

Quando utilizar

 Utilize este padrão quando:

  • For necessário representar hierarquias partes-todo de objetos;

  • For planejado que os clientes sejam capazes de ignorar as diferenças entre objetos (como itens e subitens);

  • For necessário construir estruturas de árvore para categorizar, classificar ou organizar abstrações sistêmicas;

Estrutura do padrão

Onde:

  • Component: Define a interface para os objetos da composição, implementa o comportamento padrão para todas as classes relacionadas, declara interface para acessar e gerenciar os seus componentes filhos e opcionalmente define uma interface para acessar o pai de um componente através de uma estrutura recursiva (neste caso inversa do filho para o pai).

  • Leaf: Representa o objeto da extremidade da estrutura, ou seja, os objetos não possuem filhos.

  • Composite: Representa objetos que possuem filhos ou que são filhos, define o comportamento para os componentes que têm filhos, armazena componentes filho, implementa operações relacionadas com os filhos presentes na interface de Component.

  • Client: Manipula objetos na composição através da interface de Component.

Exemplo

        No exemplo abaixo, trabalharemos com o padrão composite montando uma árvore de produtos que podem ser organizados por categorias, além de poderem ser transferidos de uma categoria para outra ou ainda para uma subcategoria.

using System;
using System.Collections.Generic;
 
namespace Sample
{
    /// <summary>
    /// Author:     Carlos Pisani
    /// Date:       April, 17,2011
    /// 
    /// Descrp.:    At this class we use Composite pattern to assembly
    ///             products tree structures, observe that  all objects
    ///             are treat identically, observe too that is very easy
    ///             work with structures and substrutures, we created 
    ///             only  WriteAllChildrenName and GetChild methods, but
    ///             we would be created inumerous another, like item 
    ///             ordenation or manipulation
    /// 
    /// Descrição:  Nesta classe utilizamos o padrão Composite para montar 
    ///             estruturas de árvore de produtos, observe que com o 
    ///             padrão, todos os objetos são tratados de forma 
    ///             identica, observe também como fica facil trabalhar
    ///             com as estruturas e subestruturas, criamos somente o 
    ///             metodo WriteAllChildrenName e GetChild, mas poderiamos
    ///             ter criado inúmeros outros, como o de manipulação 
    ///             ou ordenação de itens
    /// </summary>
    internal class Program
    {
        private static void Main(string[] args)
        {
            //Creating data
            ProductCategory myProductTree = 
                new Category(){Name="Root"};
            
            Category typeA = 
                new Category() {Name = "Type A"};
            
            Category typeB = 
                new Category() {Name = "Type B"};
            
            Category subTypeA = 
                new Category() {Name = "Sub Type A"};
            
            Category subTypeB = 
                new Category() {Name = "Sub Type B"};
 
            Product p1 = new Product(){Name = "P1"};
            Product p2 = new Product(){Name = "P2"};
            Product p3 = new Product(){Name = "P3"};
            Product p4 = new Product(){Name = "P4"};
            Product p5 = new Product(){Name = "P5"};
            Product p6 = new Product(){Name = "P6"};
            Product p7 = new Product(){Name = "P7"};
 
            //Populating the tree
            subTypeA.Add(p1);
            subTypeA.Add(p2);
            subTypeB.Add(p3);
            subTypeB.Add(p4);
            subTypeB.Add(p5);
 
            typeA.Add(p6);
            typeA.Add(subTypeA);
            typeB.Add(subTypeB);
 
            myProductTree.Add(p7);
            myProductTree.Add(typeA);
            myProductTree.Add(typeB);
 
            Console.WriteLine("Products in SubTypeA");
            subTypeB.WriteAllChildrenName();
            
            Console.WriteLine("\nAll products in the tree");
            myProductTree.WriteAllChildrenName();
 
            Console.Read();
        }
    }
 
    /// <summary>
    /// EN: This class represents the Component object
    /// PT: Esta Classe representa o objeto Component
    /// </summary>
    public interface ProductCategory
    {
        string Name { get; set; }
 
        List<ProductCategory> GetChild();
 
        void Add(ProductCategory productCategory);
 
        void Remove(ProductCategory productCategory);
 
        void WriteAllChildrenName();
    }
 
    /// <summary>
    /// EN: This class represents the Composite object
    ///     take a look here the WriteAllChildrenName
    ///     method returns the objects name inside 
    ///     its list and invoke the child WriteAllChildrenName 
    ///     (recursive), this way all objects name on the structure
    ///     or on the substructure will be write
    /// 
    /// PT: Esta Classe representa o objeto Composite
    ///     observe aqui o método WriteAllChildrenName
    ///     retorna o nome de todos os objeto da sua
    ///     lista e invoca o método WriteAllChildrenName
    ///     dos seus filhos recursivamente, desta forma
    ///     todos os nomes de objetos da estrutura ou da subestrutura
    ///     serão escritos
    /// </summary>
    public class Category : ProductCategory
    {
 
        private List<ProductCategory> Categories 
            = new List<ProductCategory>();
 
 
        #region ProductCategory Members
 
        public string Name { get; set; }
 
        public List<ProductCategory> GetChild()
        {
            return Categories;
        }
 
        public void WriteAllChildrenName()
        {
            foreach (ProductCategory p in GetChild())
            {
                Console.WriteLine(p.Name);
 
                if (!(p is Product))
                    p.WriteAllChildrenName();
            }
        }
        
        public void Add(ProductCategory productCategory)
        {
            Categories.Add(productCategory);
        }
 
        public void Remove(ProductCategory productCategory)
        {
            Categories.Remove(productCategory);
        }
 
        #endregion
    }
 
    /// <summary>
    /// EN: This class represents the Leaf object
    ///     take a look here the WriteAllChildrenName
    ///     method returns only the object name
    ///     because this is the last object of the
    ///     tree
    /// 
    /// PT: Esta Classe representa o objeto Leaf
    ///     observe que aqui o metodo WriteAllChildrenName
    ///     retorna somente o próprio nome do objeto
    ///     pois ele é o ultimo item da árvore
    /// </summary>
    public class Product:ProductCategory
    {
        public string Name { get; set; }
 
        public List<ProductCategory> GetChild()
        {
            return null;
        }
 
        public void WriteAllChildrenName()
        {
            Console.WriteLine(Name);
        }
 
        public void Add(ProductCategory productCategory)
        {
            throw new Exception("Products can't has children.");
        }
 
        public void Remove(ProductCategory productCategory)
        {
            throw new Exception("Products can't has children.");
        }
    }
}

 

Ajude a melhorar este post

         Se você tiver alguma dúvida, comentário ou sugestão, por favor comente o Post ou me envie um e-mail com assunto "Blog + [Tema]" em um dos endereços:

       Peço também que classifique este post (basta clicar nas estrelas abaixo para pontuar de um a cinco), esta é a maneira mais adequada para melhorar cada vez mais o conteúdo do blog.



About the author

Sou um arquiteto de software,  ativo na área de desenvolvimento de soluções tecnológicas a mais de 15 anos.

Nestes anos projetei inúmeras soluções para empresas de médio e grande porte bem como multinacionais.

Saiba de todas as novidades do meu blog pelo Twitter, o meu id é @carlospisani.

Você pode tirar suas dúvidas, postando no blog ou por um dos meus emails: mentters@hotmail.com ou mentters@gmail.com ou cpisani@mentters.com por favor coloque no assunto do email Blog + assunto, respondo todos os emails recebidos e sempre priorizo os leitores do blog.

 

Month List

Most comments

term vs whole life insurance term vs whole life insurance
28 comments
us United States
tongue scrapers tongue scrapers
24 comments
Best Luggage Best Luggage
24 comments
us United States

Widget Twitter not found.

Root element is missing.X

Widget Twitter not found.

Root element is missing.X

Sign in