Neste artigo, veremos dois dos 23 padrões definidos no livro “Design Patterns Elements of Reusable Object-Oriented Software”: o padrão Composite e o padrão Chain of Responsibility. Explicaremos como eles podem ser utilizados visando melhorar a forma com que nossas aplicações são desenvolvidas.
Para que serve
Reuso de soluções e documentações bem conhecidas fazem parte da principal meta em se utilizar design patterns. Neste artigo, teremos foco em padrões que nos ajudem a desenhar nossas aplicações de forma que sejam mais fáceis de manter e permitir extensão.
Em que situação o tema é útil
Composite pode ser utilizado para se ter uma forma única de tratar diferentes objetos, sendo que eles podem ser primitivos ou compostos. Já o Chain of Responsibility define uma cadeia onde uma requisição é trafegada, permitindo que ela seja analisada e processada pelo respectivo elemento responsável.
Resumo do DevMan
O artigo foca na apresentação e demonstração de uso dos padrões Composite e Chain of Responsibility, definidos pelo GoF (“Gang of Four”). Serão mostrados os seus conceitos e aplicações, além de três exemplos de código simples, porém práticos, para auxiliar o leitor no entendimento.
A importância em se ter padrões
O que seria dos desenvolvedores .NET se não pudessem reutilizar componentes desse framework nas aplicações? Se, para mostrar uma mensagem na tela, não fosse possível contar com uma classe como System.Windows.Forms.MessageBox, e fosse necessário recriar o código que o faça em cada novo sistema? Teríamos que ter, no mínimo, muitas horas para gastar. De uma maneira similar, o que seria de nós se não tivéssemos padrões a serem seguidos? Se para cada nova aplicação, tivéssemos que repensar qual a estrutura a ser usada na hora de programar para deixar o código mais fácil de entender, modificar e estender? É neste momento que design patterns fazem sentido, pois eles provêm soluções estruturadas e bem testadas na vida real, com uma documentação de domínio público. Com isso, poupamos nosso esforço em muitas atividades, permitindo que nosso tempo seja mais bem utilizado dentro dos nossos projetos (que convenhamos, eles sempre têm uma expectativa de entrega do cliente menor que o prazo que gostaríamos de ter).
Muitos padrões de programação foram catalogados no livro “Design Patterns: Elements of Reusable Object-Oriented Software”, escrito por Erich Gamma, Richard Helm, Ralph Johnson e John Vlissides (“Gang of Four”), lançado em 1995. São dessa obra que foram retirados os padrões que aqui serão apresentados, mas ela não é a única fonte desse tipo de informação. “Patterns of Enterprise Application Architecture” de Martin Fowler e “Applying UML and Patterns - An Introduction to Object-Oriented Analysis and Design and Iterative Development” de Craig Larman são outras obras que abordam o assunto.
Conceitualizando o padrão Composite
Podemos dizer que o Composite é um padrão “justo”, pois o seu objetivo é tratar diferentes objetos da mesma maneira, sejam eles classes distintas ou mesmo agrupamentos desses próprios objetos, desde que estejam organizados em uma estrutura de árvore (hierárquica).
Imagine um sistema de folha de pagamento, onde é necessário calcular aumento de salários para os funcionários de uma empresa. Podemos ter um aumento de salário para uma única pessoa, ou um aumento de salário para toda uma categoria. Note que neste caso cada funcionário representaria um objeto individual, e a categoria representaria um agrupamento, uma composição desses objetos individuais.
Outro exemplo que podemos dar, e que será utilizado na demonstração de código para este pattern, é uma estrutura de diretórios e arquivos. Esta é a situação que está descrita na Figura 1 onde podemos ver os relacionamentos entre os objetos. Cada arquivo é um objeto individual, e cada diretório é uma composição de arquivos e até mesmo outros diretórios.
Figura 1. Estrutura em árvore - diretórios e arquivos
Mas até aqui não comentamos uma das principais características deste padrão: estes elementos devem ser acessados de uma mesma forma, tanto faz se é um objeto individual ou se é uma composição. Para chegar neste objetivo, todos eles devem compartilhar uma mesma interface ou herdar de uma mesma classe abstrata, de forma que todos possuam os mesmos métodos. Ainda no exemplo de uma hierarquia de pastas e arquivos, cada objeto pode ter um método para retornar o espaço em disco que ele ocupa. É claro que a implementação desse método será diferente entre objetos que representam um diretório e os que representam arquivos. Como um diretório em si não ocupa espaço em disco, este método de cálculo pode ser feito a partir do resultado da chamada deste mesmo método executada em cada arquivo contido na pasta.
Vejamos a Figura 2, que é a representação deste padrão. Temos uma classe abstrata comum, Component. Note que o Composite possui, como atributo, uma lista de objetos do tipo Component. Desta forma é que podemos manter a estrutura hierárquica contida neste pattern. Além disso, o cliente acessa apenas a classe abstrata / interface Component, para que todos os objetos possam ser tratados de forma uniforme.
Outra questão importante é que a classe Composite redireciona as chamadas das operações definidas na interface / classe abstrata que ela recebe para seus filhos. Isso significa que, ao se chamar o método Operation de Composite, serão chamados também os mesmos métodos Operation de todos os filhos que a instância dessa classe possuir.
Figura 2. Definição dopattern Composite
Em resumo:
• Component – é uma classe abstrata ou interface que declara os métodos comuns que serão utilizados pelo cliente para acessar os objetos de uma maneira uniforme;
• Leaf – dentro da estrutura em árvore que é criada por este padrão, esta classe representa uma “folha”, ou seja, um objeto individual que não possui filhos dentro da hierarquia;
• Composite – é o objeto que agrupa os demais objetos que realizam a classe / interface, e que propaga a execução das suas operações para as respectivas operações dos seus filhos. Antes e após essa propagação de métodos, é permitido que sejam efetuados outros processamentos adicionais.
Recuperando espaço consumido – exemplo
Nosso exemplo para demonstrar o padrão Composite será uma aplicação que retorna a quantidade de espaço em disco consumido pelos arquivos que estão guardados em um diretório do Windows. Note que esse cálculo não deve apenas considerar o tamanho dos arquivos que estão diretamente dentro da pasta, mas também o tamanho dos arquivos que estão dentro de suas subpastas e assim por diante.
O primeiro código que temos é a Listagem 1, que mostra a interface que define todas as operações que serão utilizadas para manipular, de modo único, as classes que representam diretórios e arquivos.
Listagem 1. Interface IRecurso
using System;
namespace Composite
{
public interface IRecurso
{
string Caminho { get; set; }
long ObterTamanho();
}
}
Esta interface possui duas operações. Uma é a propriedade Caminho, que será utilizada para armazenar o caminho do diretório ou pasta (exemplo: C:\temp\ ou C:\temp\arquivo.txt). O outro método, ObterTamanho, será responsável por retornar o tamanho em bytes que é ocupado no disco, seja por um arquivo ou por um diretório inteiro.
Note que neste exemplo eu não estou utilizando uma classe abstrata, mas sim uma interface. É uma preferência pessoal, pois poderíamos utilizar a classe abstrata da maneira que está descrito no modelo de classes que vimos na Figura 2. Inclusive, se trabalharmos com essa herança, nós ganhamos a possibilidade de definir comportamentos padrão para os métodos, ou seja, só precisaríamos efetuar a sobrecarga dos métodos que realmente nos interessam. Mas como disse, a utilização de uma interface é uma preferência minha.
Desta vez, nesta demonstração, eu quero mudar um pouco a ordem como apresento cada pedaço do código de exemplo, colocando o trecho final agora no meio da explicação. Com isso, eu quero mostrar que o cliente faz acesso aos métodos definidos na interface de modo que para ele tanto faz se estamos lidando com um objeto que representa um diretório ou um arquivo.
...Confira outros conteúdos:
Teste unitário com NUnit
Como migrar projetos do ASP.NET MVC...
Crie relatórios com o Stimulsoft...
Promoção de Natal
Oferta exclusiva de Natal!
Pagamento anual
12x no cartão
De: R$ 69,00
Por: R$ 59,90
Total: R$ 718,80
Garanta o desconto
- Formação FullStack Completa
- Carreira Front-end I e II, Algoritmo e Javascript, Back-end e Mobile
- +10.000 exercícios gamificados
- +50 projetos reais
- Comunidade com + 200 mil alunos
- Estude pelo Aplicativo (Android e iOS)
- Suporte online
- 12 meses de acesso
Pagamento recorrente
Cobrado mensalmente no cartão
De: R$ 79,00
Por: R$ 59,90 /mês
Total: R$ 718,80
Garanta o desconto
- Formação FullStack Completa
- Carreira Front-end I e II, Algoritmo e Javascript, Back-end e Mobile
- +10.000 exercícios gamificados
- +50 projetos reais
- Comunidade com + 200 mil alunos
- Estude pelo Aplicativo (Android e iOS)
- Suporte online
- Fidelidade de 12 meses
- Não compromete o limite do seu cartão
<Perguntas frequentes>
Nossos casos de sucesso
Eu sabia pouquíssimas coisas de programação antes de começar a estudar com vocês, fui me especializando em várias áreas e ferramentas que tinham na plataforma, e com essa bagagem consegui um estágio logo no início do meu primeiro período na faculdade.
Estudo aqui na Dev desde o meio do ano passado!
Nesse período a Dev me ajudou a crescer muito aqui no trampo.
Fui o primeiro desenvolvedor contratado pela minha
empresa. Hoje eu lidero um time de desenvolvimento!
Minha meta é continuar estudando e praticando para ser um
Full-Stack Dev!
Economizei 3 meses para assinar a plataforma e sendo sincero valeu muito a pena, pois a plataforma é bem intuitiva e muuuuito didática a metodologia de ensino. Sinto que estou EVOLUINDO a cada dia. Muito obrigado!
Nossa! Plataforma maravilhosa. To amando o curso de desenvolvimento front-end, tinha coisas que eu ainda não tinha visto. A didática é do jeito que qualquer pessoa consegue aprender. Sério, to apaixonado, adorando demais.
Adquiri o curso de vocês e logo percebi que são os melhores do Brasil. É um passo a passo incrível. Só não aprende quem não quer. Foi o melhor investimento da minha vida!
Foi um dos melhores investimentos que já fiz na vida e tenho aprendido bastante com a plataforma. Vocês estão fazendo parte da minha jornada nesse mundo da programação, irei assinar meu contrato como programador graças a plataforma.
Wanderson Oliveira
Comprei a assinatura tem uma semana, aprendi mais do que 4 meses estudando outros cursos. Exercícios práticos que não tem como não aprender, estão de parabéns!
Obrigado DevMedia, nunca presenciei uma plataforma de ensino tão presente na vida acadêmica de seus alunos, parabéns!
Eduardo Dorneles
Aprendi React na plataforma da DevMedia há cerca de 1 ano e meio... Hoje estou há 1 ano empregado trabalhando 100% com React!
Adauto Junior
Já fiz alguns cursos na área e nenhum é tão bom quanto o de vocês. Estou aprendendo muito, muito obrigado por existirem. Estão de parabéns... Espero um dia conseguir um emprego na área.
Utilizamos cookies para fornecer uma melhor experiência para nossos usuários, consulte nossa política de privacidade.