GoF – Chain of Responsibility

MassaWhat?!

Massaroca: Mistura, farofa, UNION ALL.

O que aconteceria se você pegasse os Patterns mais práticos juntamente com noções de biologia e neurologia, colocasse tudo em um caldeirão com feijão preto e deixasse cozinhar até o ponto de ebulição? Te digo o seguinte, a chance disto dar certo é absurdamente alta! Sério!

Senta que lá vem história

No desafio de encontrar uma resposta para uma solução arquitetural que permitisse o máximo desacoplamento entre os membros envolvidos em uma determinada ação ou comportamento resolvi dar uma inovada no processo de tomada de decisão neste aspecto.

Para tanto, optei por tentar perguntar à minha namorada como ela acreditaria ser a forma correta de organizar as partes componentes de um sistema. Apenas para constar, minha namorada é formada em publicidade e propaganda e, o mais perto que ela já chegou de análise e desenvolvimento de sistemas foi me beijando enquanto eu estava com o Visual Studio aberto. (ok, foi fraca…)

Bom, para tanto eu precisava estabelecer uma forma de conseguir me comunicar com ela de forma que eu pudesse me fazer entender e ao mesmo tempo, fazer com que a resposta dela tivesse alguma utilidade prática. Esta situação me lembrou um episódio de uma das séries de TV que eu mais gosto onde o Dr. House se encontra desprovido de uma equipe e recorre a uma “pessoa normal” para ajudá-lo a resolver um caso. A idéia era basicamente esta…

De imediato, por algum motivo (talvez até mesmo meu subconsciente lembrando do Dr. House), decidi utilizar o corpo humano como linguagem intermediária para expor minha abstração do problema. Começamos então, eu e ela,  uma das discussões mais estranhas da minha vida.

Sabendo o quão brilhante e inteligente ela é, eu já deveria ter deduzido que esta conversa teria um final feliz, eu não imaginava porém que seria tão rápida e facilmente. Coisa de uma dúzia de frases foram ditas até que o seguinte diálogo acontecesse…

Eu – Olha só, eu preciso entender como a mão sabe que é pra se mover; Preciso fazê-la se mover de forma que, a mão ao fazer isto, não precise que eu diga se ela é a mão esquerda ou direta, ou mesmo, no caso de eventualmente eu perdê-la em um acidente o corpo continue funcionando adequadamente com o menor impacto possível, e, se possível permitir que eu substitua esta mão por qualquer outra mão, seja ela humana, pata de vaca, galinha ou qualquer coisa q eu decida colocar ali…

Ela (prontamente) – A mão não tem que saber que está ali.

E foi isto. Esta é a teoria, a minha bandeira atual. A genialidade da simplicidade que eu estava procurando… “A mão não tem que saber que está ali” representa exatamente meu conceito de componentes burros. Eu posso ter uma, duas, dez ou nenhuma mão. A mão não depende do corpo para saber de suas capacidades assim como o corpo não depende de orgão ou membro algum para saber de suas responsabilidades; Na verdade, o corpo nada mais é que um catado de entidades, no caso células, que juntas formam todos os órgãos, estruturas, ligamentos e terminações que nos fazem seres vivos. A única premissa é de que as células interajam entre si de forma a se representarem em um conjunto coerente onde informações e comportamentos possam ser compreendidos e uteis para o todo.

Terra chamando…

Estabelecer um paralelo entre toda esta viagem com relação ao corpo humano e sua aplicabilidade na tecnologia tem se mostrado muito mais abrangente e assertivo que eu poderia ter imaginado na noite em que conversei sobre o assunto com a “Dona da pensão”.

Inicialmente queria colocar no papel uma forma de mapear o fluxo de informações que partem ou chegam ao cérebro a fim de serem processadas ou deflagrarem algum comportamento específico. No primeiro dia de busca deste modelo pensei em agendar uma visita a um neurologista e bater um papo franco com ele sobre minha piração, porém, um biólogo que está defendendo uma tese sobre o funcionamento da memória apareceu no meu Gtalk antes (obrigado rtmazzeo pela ajuda e a Jung pela explicação do ocorrido); Segue uma parte da conversa que tive com ele:

“…15:19 rtmazzeo: toda informação é um sinal eletrico
15:20 entaum o padrão seria o mesmo para tudo
o que muda é como uma determinada estrutura interpreta
se vc cruzar os sinais
tipo o sinal luminoso entrar em uma outra via
ex. auditiva
vc “escuta” a luz como se fosse o som
15:21 isso tem o nome de sinestesia
entaum basicamente os sinais são os mesmos
…”

Ok, perfeito! Basicamente o que descobri é que dentro do corpo humano, entre suas estruturas seja ela qual for, existe uma mensagem com um formato padrão sendo enviada, recebida, interpretada e, quando necessário, realizando o caminho reverso passando pelo mesmo processo. Acho que não preciso dizer como isto é básico em TI, preciso?

Básico ou não, precisava começar a implementar algo utilizando esta e outras analogias e abstrações que eu já tinha em mãos, é ai que entram os padrões da tão famosa e aclamada GoF.

CoR na Prática

Pra quem conhece, ouviu falar e/ou leu o livro Design Patterns: Elements of Reusable Object-Oriented Software,  é de lá que grande parte da técnica que usei para representar as diversas facetas do corpo foram tiradas, como este artigo é especificamente sobre o padrão Chain of Responsibility, tentarei ao máximo me ater a ele mas não prometo nada.

Mas o que vem a ser este padrão? A Wikipedia diz o seguinte:

O padrão de projeto de software, Chain of Responsibility, fornece um acoplamento mais fraco. Evita o acoplamento do remetente de uma solicitação ao seu receptor, ao dar a mais de um objeto a oportunidade de tratar a solicitação. Encadear os objetos receptores, passando a solicitação ao longo da cadeia até que um objeto a trate. Utilizar quando:

  • mais de um objeto pode tratar uma solicitação e o objeto que a tratará não é conhecido a priori.
  • o objeto que trata a solicitação deve ser escolhido automaticamente;
  • deve-se emitir uma solicitação para um dentre vários objetos, sem especificar explicitamente o receptor;
  • o conjunto de objetos que pode tratar uma solicitação deveria ser especificado dinamicamente.

Desenhando, tudo fica mais fácil:

Interfacear é a chave

Interfacear é a chave

Explicitamente o que acontece é que cada uma das estruturas trabalha com um objeto que implementa a interface Impulso (Vide snipet abaixo) o qual contém tanto uma referência à estrutura de Origem,  Destino e claro, a Informação que está sendo trafegada; Um detalhe importante é que a própria estrutura possui especializações que tratam de definir se aquele dado impulso é algo que deva ser tratado por ela ou não, tarefa esta desempenhada pelos métodos PodeConduzir e PodeReceber.

Com este raciocínio em mente, podemos fazer uma implementação básica destas interfaces da seguinte maneira:

///
/// Representa um sinal enviado pelo nervo ao encéfalo
///
public interface IImpulso
{
///
/// Estrutura de origem do Impulso.. Precisa necessariamente
/// implementar as capacidades neurais de recepção expressas pela interface IAxonio
///
IAxonio Origem { get; }

///
/// Estrutura que receberá e realizará o processamento do impulso. Precisa necessariamente
/// implementar as capacidades neurais de recepção expressas pela interface IDendrito
///
IDendrito Destino { get; set; }

///
/// Informação que está sendo trafegada
///
IInformacao Informacao { get; set; }
}
public class Impulso : IImpulso
    {
        /// <summary>
        /// Cria uma nova instância do objeto de impulso padrão
        /// </summary>
        /// <param name="origem">Axonio que está originando o impulso</param>
        public Impulso(IAxonio origem)
        {
            this.Origem = origem;
        }

        /// <summary>
        /// Referência para o axionio que originou o impulso
        /// </summary>
        public IAxonio Origem { get; private set; }

        /// <summary>
        /// Dendrito ao qual a informação se destina
        /// </summary>
        public IDendrito Destino { get; set; }

        /// <summary>
        /// Informação relevante
        /// </summary>
        public IInformacao Informacao { get; set; }
    }

A implementação do impulso deve ser a mais simplista possível uma vez que ele em si é apenas um “meio” de comunicação entre as estruturas das quais exemplarmente representarei um Axônio que é o prolongamento nervoso responsável por conduzir impulsos a outras estruturas do corpo, seja esta um Dendrito, neurônio,  membro ou um órgão qualquer.

Neste exemplo estou considerando que meus Axonios serão utilizados por meio de REST e serão ativados quando um impulso tenha sido gerado por um acesso via POST.

/// <summary>
    /// Parte do neurôrio que atua como condutor de impulsos que partem do corpo celular até uma outra
    /// estrutura seja ela um neurônio ou qualquer outra célula capaz de interpretar a mensagem
    /// </summary>
    public interface IAxonio : IProlongamento
    {
        /// <summary>
        /// Verifica se o axionio pode conduzir um dado impulso
        /// </summary>
        /// <param name="impulso">Impulso que necessitar ser conduzido</param>
        /// <returns>Se o axonio consegue conduzir o impulso</returns>
        bool PodeConduzir(IImpulso impulso);

        /// <summary>
        /// Conduz as informações de um dado impulso até um destino qualquer
        /// </summary>
        void Conduz(IImpulso impulso);
    }

Visto que estamos utilizando REST, minha implementação da interface de informação pode ser tida como se segue (rascunho):

public abstract class BaseInformacao : IInformacao
    {
        /// <summary>
        /// Retorna o indice do qual a aplicação lerá as informações REST
        /// </summary>
        protected abstract int IndiceLeituraUrl { get; }

        /// <summary>
        /// Tipo do request (GET / POST)
        /// </summary>
        public string RequestType { get; set; }

        /// <summary>
        /// Url atual
        /// </summary>
        public Uri Url { get; set; }

        /// <summary>
        /// Contexto da execução
        /// </summary>
        public HttpContext Contexto { get; set; }

        /// <summary>
        /// Nome mapeado do handler requisitado
        /// </summary>
        public string NomeHandler
        {
            get
            {
                return this.RetornaNomeHandler();
            }
        }

        /// <summary>
        /// Nome do assembly de destino
        /// </summary>
        public string NomeAssembly { get; set; }

        /// <summary>
        /// Nome do neuronio requisitado
        /// </summary>
        public string NomeNeuronio
        {
            get
            {
                return this.RetornaNomeNeuronio();
            }
        }

        /// <summary>
        /// Coleta parâmetros passados na url
        /// </summary>
        private ParametrosCollection _parametros = null;
        public ParametrosCollection Parametros
        {
            get
            {
                return (_parametros == null) ? this.RetornaParametros() : _parametros;
            }
            set { _parametros = value; }
        }

        /// <summary>
        /// Coleta parâmetros passados na url
        /// </summary>
        /// <returns>Parametros passados na url</returns>
        private ParametrosCollection RetornaParametros()
        {
            ParametrosCollection parametros = new ParametrosCollection();
            int indice = (this.Url.AbsoluteUri.Contains("localhost") ? 4 : (this.IndiceLeituraUrl + 2));
            if (this.Url.Segments.Length > indice)
            {
                for (int i = indice; i < this.Url.Segments.Length; i++)
                {
                    string[] fragmentos = this.Url.Segments[i].Split('=');
                    if (fragmentos.Length == 2)
                    {
                        parametros.Add(
                            new ParametroDTO
                            {
                                Nome = fragmentos[0],
                                Valor = fragmentos[1].Replace("/", string.Empty)
                            });
                    }
                    else
                    {
                        parametros.Add(
                            new ParametroDTO
                            {
                                Nome = fragmentos[0],
                                Valor = null
                            });
                    }
                }
            }
            return parametros;
        }

        /// <summary>
        /// Verifica o nome do neurônio requisitado via REST
        /// </summary>
        /// <returns>Nome do neurônio concatenado com o prefixo adequado</returns>
        private string RetornaNomeNeuronio()
        {
            string nomePrologamento = string.Empty;
            int indice = (this.Url.AbsoluteUri.Contains("localhost") ? 3 : (this.IndiceLeituraUrl + 1));
            if (this.Url.Segments.Length > indice)
            {
                nomePrologamento = this.Url.Segments[indice];
            }
            return nomePrologamento.Replace("/", string.Empty);
        }

        /// <summary>
        /// Verifica o nome do handler requisitado via REST
        /// </summary>
        /// <returns>Nome do handler concatenado com o prefixo Ne de identificação de neuronios</returns>
        private string RetornaNomeHandler()
        {
            string nomeNeuronio = string.Empty;
            int indice = (this.Url.AbsoluteUri.Contains("localhost") ? 2 : this.IndiceLeituraUrl);
            if (this.Url.Segments.Length > indice)
            {
                nomeNeuronio = this.Url.Segments[indice];
            }
            return nomeNeuronio.Replace("/", string.Empty);
        }

        /// <summary>
        /// Serializa as informações para o formato SqlCommand
        /// </summary>
        /// <returns></returns>
        public abstract SqlCommand ToSqlCommand();
    }

No caso do .Net, se você não está utilizando WCF ou mesmo o MVC, a melhor forma de se trabalhar com REST é implementar a interface IHttpHandlerFactory fazendo com que a mesma dispare, no caso, um neurônio com o conhecimento relacionado à ação ou requisição que está sendo feita pelo usuário. Esta intenção claro, se fará transparente por meio de um impulso contendo a informação necessária para o processamento por parte das estruturas relacionadas e capazes de tratar o mesmo.

Uma implementação simplista deste neurônio / Handler seria a seguinte:

/// <summary>
    /// Composição básica de um neurônio que contém basicamente axionios e Dentritos, estruturas
    /// responsáveis por proporcionar meios para comunicação entre neuronios
    /// </summary>
    public interface INeuronio : ICelula, IAxonio, IDendrito
    {
        /// <summary>
        /// Conduz impulsos entre o neuronio até
        /// </summary>
        List<IAxonio> Axionios { get; }

        /// <summary>
        /// Recebe e processa Impulsos provenientes de outroas estruturas / neuronios
        /// </summary>
        List<IDendrito> Dendritos { get; }
    }
/// <summary>
    /// Estrutura básica de um neurônio
    /// </summary>
    public abstract class Neuronio : INeuronio
    {
        /// <summary>
        /// Axionios que compoem o neurônio (condução)
        /// </summary>
        public abstract List<IAxonio> Axionios { get; }

        /// <summary>
        /// Dendritos que compoem o neurônio (recepção)
        /// </summary>
        public abstract List<IDendrito> Dendritos { get; }

        /// <summary>
        /// Membrana que envolve e controla o neuronio
        /// </summary>
        public virtual IMembranaCelular MembranaCelular
        {
            get { return new MembranaCelular(); }
        }

        /// <summary>
        /// Condux o impulso utilizando o Axionio correto
        /// </summary>
        /// <param name="impulso">Impulso que será enviado</param>
        public virtual void Conduz(IImpulso impulso)
        {
            if (this.PodeConduzir(impulso))
            {
                foreach (IAxonio axonio in this.Axionios)
                {
                    if (axonio.PodeConduzir(impulso))
                    {
                        axonio.Conduz(impulso);
                    }
                }
            }
        }

        /// <summary>
        /// Recebe o impulso utilizando o dendrito adequado
        /// </summary>
        /// <param name="impulso">Impulso sendo recebido</param>
        public virtual void Recebe(IImpulso impulso)
        {
            if (this.PodeReceber(impulso))
            {
                foreach (IDendrito dendrito in this.Dendritos)
                {
                    if (dendrito.PodeReceber(impulso))
                    {
                        dendrito.Recebe(impulso);
                    }
                }
            }
        }

        /// <summary>
        /// Define qual ou não o neurônio pode receber um dado tipo de impulso
        /// </summary>
        /// <param name="impulso">Impulso que está sendo recebido</param>
        /// <returns>Se o neurônio é capaz ou não de tratar o impulso</returns>
        public abstract bool PodeReceber(IImpulso impulso);

        /// <summary>
        /// Define qual ou não o neurônio pode conduzir um dado tipo de impulso
        /// </summary>
        /// <param name="impulso">Impulso que está sendo transmitindo</param>
        /// <returns>Se o neurônio é capaz ou não de tratar o impulso</returns>
        public abstract bool PodeConduzir(IImpulso impulso);
    }

Bom, acho que já escrevi o suficiente.. O negócio é o seguinte, precisava passar o recado com relação a parilidade existente entre o corpo humano e uma arquitetura de sistemas qualquer e, a importancia desta visão utilizando um exemplo o mais simples possível.

Nos próximos artigos pretendo abordar mais direta e profundamente este relacionamento em temas como: Gravação e persistencia de dados desnormalizados, validação e direcionamento de impulsos, funcionamento do encéfalo, a importancia da membrana celular, recriando um sistema neural de alto nível, etc… É sério, estes são os assuntos de alguns post que estão por vir.

Espero que tenha feito uma boa leitura e até a próxima…

Leia também:  Redes Neurais C# e Redes Neuras C# – Hopfield

rtmazzeo

2 comentários

  1. Opa… isso me lembrou bem no nosso framework aqui (no que diz respeito as palavras ‘origem e destino’, heheh),,,
    Nossa aplicação web é baseada em transações (acho q não encaixa perfeitamente na tua arquitetura).

    Enfim, todas as transações possuem a Origem-Destino-Dados,, tudo trafegando em string. Simples assim… Mas ninguém comanda ninguém diretamente, é como se fosse uma carta: Vc envia pro correio e o correio envia para o destinatário.

    Bom, neste exemplo o correio existe por questões de segurança.. =]

    P.S.: Tudo que está por baixo do IIS (Internet Informatio Services) é COBOL. O framework COBOL trabalha junto com o IIS (Servidor de aplicação).

    []’s

    Curtir

    • É, na verdade, não faz muito sentido do ponto de vista OOP que seus objetos saibam que são os consumidores e destinatários de seus serviços.. tudo bem que os provadores de informação se conheçam mas acaba ae o acoplamento… Neste caso eu vejo este comportamento com uma extensão mais grosseira do objeto, onde um não existe sem o outro.

      Curtir

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s

%d blogueiros gostam disto: