C# - Padrões Estruturais Gof - Composite
Neste artigo vou apresentar com o padrão estrutural Gof Composite. |
O padrão de projeto Composite compõe objetos em estruturas de árvore para representar hierarquias parte-todo.
Esse padrão permite que os clientes tratem objetos individuais e composições de objetos uniformemente compondo objetos em uma estrutura de árvore e, em seguida, trabalhar com essa estrutura como se fosse um único objeto.
O uso desse padrão de design faz sentido o problema que queremos resolver pode ser representado como uma estrutura semelhante a uma árvore. Sendo que a aplicação do padrão Composite permite executar métodos recursivamente em toda astrutura da árvore resumindo os resultados.
Como exemplo de aplicação do Composite temos o seguinte cenário :
Para ilustrar
vamos pensar nas partes de um computador
Um computador é feito de várias partes ou elementos integrados entre si,
conforme mostrado na figura (de forma bem resumida)
Como mostra a imagem temos vários objetos que juntos formam o computador: o
Gabinete, Periféricos, Disco rígido, Mouse, Teclado, CPU, Memória, etc.,
tudo são objetos.
Neste contexto um objeto Composite ou objeto
composto(fazendo a tradução livre) é um objeto que contem outros objetos. E
devemos lembrar que um objeto Composite também pode conter outros objetos
compostos criando um hierarquia de objetos. Quando um objeto não contiver nenhum
outro objeto ele é simplesmente tratado como um objeto
primitivo ou Leaf
que numa tradução livre seria a Folha.
Assim aplicando este conceito ao nosso exemplo podemos identificar os
Composite object (objetos compostos por outros
objetos) como sendo: Computador, Gabinete, Periféricos e Placa Mãe.
E podemos identificar os objetos folha ou Leaf object
(objetos primitivos ou folha que não são compostos por outros objetos)
como sendo: Disco Rígido, Mouse, Teclado, CPU e RAM
Destacando que todos os objetos são do mesmo tipo ou seja no exemplo eles são
dispositivos eletrônicos.
Desta forma o padrão de projeto Composite terá uma
estrutura semelhante a uma árvore com objetos compostos ou
composite objects e objetos folha ou
leaf objects.
E aqui é importante destacar como padrão atua; a ideia fundamental é que,
se você realizar alguma operação no objeto folha, a mesma operação poderá ser
realizada nos objetos compostos.
Por exemplo, se consigo obter o preço de um Mouse, devo ser capaz de obter o
preço dos Periféricos e até mesmo devo ser capaz de obter/calcular o preço do
objeto Computador.
Percebeu a navegação na hierarquia ????
E para implementar este comportamento devemos usar o
Padrão de projeto Composite.
Estrutura do padrão Composite
Desta forma na
estrutura do padrão Composite podemos identificar 3 componentes:
1- Component - Um Component
é uma interface que descreve operações comuns a elementos simples ou complexos
da árvore.
2- Leaf - Um Leaf ou
Fôlha é um único objeto, que não possui subelementos.
3- Composite - Composite
é um objeto que possui subelementos (folhas ou outros objetos compostos)
Diagrama UML
A seguir temos o diagrama UML do padrão Composite segundo o Gof:
Os participantes são:
1- Component - É Esta é a interface ou a classe abstrata que define as funções comuns que precisam ser implementadas nos objetos primitivos (Leaf) e compostos(Composite)
O Component serve como o tipo base para todos os
objetos na hierarquia.
2- Leaf - É a classe que implementa os
comportamentos padrão conforme definido por sua interface
Component. A Leaf não contém uma referência a nenhum tipo composto.
3- Composite - Contém outros objetos
compostos e implementa os métodos de Component.
Esta classe contém métodos relacionados ao gerenciamento de objetos filhos.
É uma classe
concreta que define as operações necessárias que podem ser realizadas nos
componentes filhos, ou seja, os métodos Adicionar, Remover, Obter, Encontrar,
etc.
O objeto Composite não está familiarizado com as classes concretas de seus
filhos. Ele se comunica com seus filhos por meio da interface
Component.
4- Client - Usa a interface Component
para acessar tipos compostos e executar as operações definidas de maneira
uniforme em toda a hierarquia.
Usos do padrão Composite
Podemos usar o padrão Composite quando :
Vantagens e desvantagens do padrão Bridge
As vantagens em usar o padrão são:
Como desvantagens do padrão vale destacar que a sua aplicação pode se tornar muito genérica devido à sua uniformidade, tornando difícil restringir objetos que podem ser incluídos no grupo composto.
Aplicando o padrão Composite
Veremos agora um exemplo prático de aplicação do padrão Composite.
Vamos supor que temos uma organização com diferentes departamentos, onde cada departamento possui um conjunto de funcionários, e, que precisamos coletar (ler) as horas trabalhadas registradas de cada funcionário em cada departamento, o total de horas trabalhadas por cada departamento e o total geral de horas trabalhadas na organização.
Podemos identificar aqui uma hierarquia de objetos consistida de:
1- Organização (Composite)
2- Departamentos (Composite)
3- Funcionários (Leaf)
Aqui podemos identificar a Organização como sendo o
composite que é e composto de outros objetos e Funcionários como sendo o
Leaf pois não contem subelementos.
Assim vamos aplicar o padrão Composite para
resolver o problema proposto.
Para isso vamos criar uma aplicação Console no ambiente do .NET 5.0 usando o VS 2019. A seguir temos o diagrama de classes que foi gerado pela implementação feita no VS 2019:
1- Classe HoraTrabalhada : Representa o
Component, sendo a classe base que declara a
funcionalidade comum GetHoraTrabalhada para os
objetos Funcionario (Leaf) e Organizacao (Composite).
A classe também contém os métodos Add e Remove que
poderão ser implementados;
2- A classe Funcionario : Representa o Leaf
ou Folha na estrutura da árvore que não pode ter filhos. Esta classe
implementa a classe abstrata HoraTrabalhada e
substitui o método GetHoraTrabalhada() para
retornar a hora de trabalho registrada para o funcionário;
3- A classe Organizacao : Representa o
Composite e os objetos complexos (compostos) que
podem ter Funcionario (folha)
e outro composto como seus filhos;
A seguir temos o código usado na implementação:
1- Classe abstrata HoraTrabalhada (Component)
using System;
namespace Composite1.Component |
2- Classe Funcionario (Leaf)
using Composite1.Component; using System; namespace Composite1.Leaf |
3- Classe Organizacao (Composite)
using Composite1.Component; using System; using System.Collections.Generic;
namespace Composite1.Composite |
4- Program (Client)
using Composite1.Composite; using Composite1.Leaf; using System; namespace Composite1 |
A execução do projeto irá apresentar o seguinte resultado:
Mesmo que esse
padrão possa parecer um pouco complexo, ele pode ser muito benéfico quando temos
estruturas de árvore complexas em nosso código.
Além disso, por ter uma única interface que é compartilhada por todos os
elementos no padrão Composite, o cliente não
precisa se preocupar com a classe concreta com a qual trabalha.
Pegue o código
do projeto aqui :
Composite1.zip
"Porém,
respondendo Pedro e os apóstolos, disseram: Mais importa obedecer a Deus do que
aos homens."
Atos 5:29
Referências:
NET - Unit of Work - Padrão Unidade de ...
NET - O padrão de projeto Decorator
NET - Padrão de Projeto Builder
C# - O Padrão Strategy (revisitado)
NET - O padrão de projeto Command
NET - Apresentando o padrão Repository