Remove ads
Da Wikipédia, a enciclopédia livre
Entende-se por Composite um padrão de projeto de software utilizado para representar um objeto formado pela composição de objetos similares. Este conjunto de objetos pressupõe uma mesma hierarquia de classes a que ele pertence. Tal padrão é, normalmente, utilizado para representar listas recorrentes - ou recursivas - de elementos. Além disso, este modo de representação hierárquica de classes permite que os elementos contidos em um objeto composto sejam tratados como se fossem um objeto único. Desta forma, os métodos comuns às classes podem ser aplicados, também, ao conjunto agrupado no objeto composto.
Este artigo ou secção contém uma lista de referências no fim do texto, mas as suas fontes não são claras porque não são citadas no corpo do artigo, o que compromete a confiabilidade das informações. (Outubro de 2016) |
A intenção do padrão Composite é compor objetos em estruturas de árvore para representar hierarquia partes-todo.
Por exemplo, em interfaces gráficas, um elemento gráfico pode ser formado pela composição de vários outros elementos. Uma página de internet pode conter um ou mais ícones, além de caixas de texto e vários outros elementos. Considerando que uma determinada hierarquia de classes indica um Elemento Gráfico como, portanto, a super-classe—comum à todas classes que representam elementos gráficos atômicos. Assim, a "página" pode ser representada tanto como uma classe que contém zero ou mais elementos gráficos. Veja diagrama a seguir.
Outro exemplo são as linguagens de programação. A hierarquia de classes é utilizada para representar os comandos da linguagem. Supondo que a super-classe seria "Comando", teríamos, pois, uma classe de atribuição, além de o comando while e o comando composto - constituído por uma lista de outros comandos normalmente delimitados por indicadores como { e } ou palavras reservadas como begin, end, etc. Normalmente são representados utilizando o padrão composite. Vide também o outro diagrama representado abaixo.
Vale ressaltar que é fundamental implementar cada método do objeto composto para ser aplicável à lista de objetos que possui. Logo, um objeto "cliente" faz necessário ativar o método desenha()
de um objeto do tipo "Janela". Este método deverá ser capaz de ativar o desenha()
de objeto que o contém. Desta maneira, será possível interagir com uma composição de objetos da mesma forma que se interage com objetos individuais.
O diagrama abaixo mostra a estrutura de classes do exemplo de componentes gráficos apresentada acima.
Representa-se, no diagrama de classes acima, a estrutura do padrão composite, sempre composta por uma estrutura auto-referenciada.
O diagrama abaixo mostra a hierarquia de classes pertencente ao exemplo de comandos de linguagem de programação hipotética apresentada.
As classes e objetos participantes nesse padrão são:
Imagine que você está fazendo um sistema de gerenciamento de arquivos. Como você já sabe é possível criar arquivos concretos (vídeos, textos, imagens, etc.) e arquivos pastas, que armazenam outros arquivos. O problema é o mesmo, como fazer um design que atenda estes requerimentos?
A ideia do Composite é criar uma classe base que contém toda a interface necessária para todos os elementos e criar um elemento especial que agrega outros elementos.
A classe base Arquivo implementa todos os métodos necessários para arquivos e pastas, no entanto considera como implementação padrão a do arquivo, ou seja, caso o usuário tente inserir um arquivo em outro arquivo uma exceção será disparada. Note como a classe ArquivoVideo não tem métodos.
Já na classe que representa a pasta (ArquivoComposite) nós sobrescrevemos o comportamento padrão e repassamos a chamada para todos os arquivos, sejam arquivos ou pastas.
A primeira vantagem, e talvez a mais forte, seja o fato de os clientes do código Composite serem bem simplificados, pois podem tratar todos os objetos da mesma maneira.
O exemplo a seguir, escrito em Java, implementa uma classe gráfica, na qual, pode ser uma elipse ou uma composição de diversas outras formas geometrias, que, todas podem ser representadas no gráfico.
Ele pode ser estendido para implementar diversos outras formas geográficas (círculo, quadrado, etc.) no gráfico.
/** "Component" */
interface Graphic {
//Printa o grafico.
public void print();
}
/** "Composite" */
import java.util.List;
import java.util.ArrayList;
class CompositeGraphic implements Graphic {
//Coleção de Graficos filhos
private List<Graphic> childGraphics = new ArrayList<Graphic>();
//Printa o grafico
public void print() {
for (Graphic graphic : childGraphics) {
graphic.print();
}
}
//Adiciona o grafico a composição.
public void add(Graphic graphic) {
childGraphics.add(graphic);
}
//Remove a forma geometrica da composição.
public void remove(Graphic graphic) {
childGraphics.remove(graphic);
}
}
/** "Leaf" */
class Ellipse implements Graphic {
//Printa o grafico.
public void print() {
System.out.println("Ellipse");
}
}
/** Client */
public class Program {
public static void main(String[] args) {
//Inicializa quatro elipses
Ellipse ellipse1 = new Ellipse();
Ellipse ellipse2 = new Ellipse();
Ellipse ellipse3 = new Ellipse();
Ellipse ellipse4 = new Ellipse();
//Inicializa tres componentes do grafico.
CompositeGraphic graphic = new CompositeGraphic();
CompositeGraphic graphic1 = new CompositeGraphic();
CompositeGraphic graphic2 = new CompositeGraphic();
//Faz o grafico
graphic1.add(ellipse1);
graphic1.add(ellipse2);
graphic1.add(ellipse3);
graphic2.add(ellipse4);
graphic.add(graphic1);
graphic.add(graphic2);
// Printa quatro vezes a String Ellipse ( Ele printa o grafico completo).
graphic.print();
}
}
/// Trata elementos como uma composição de um ou mais elementos, de forma que os componentes
/// possam ser separados entre si.
public interface IComposite
{
void CompositeMethod();
}
public class LeafComposite :IComposite
{
public void CompositeMethod()
{
//Faz algo.
}
}
/// Elementos de IComposite podem ser separados dos outros
public class NormalComposite : IComposite
{
public void CompositeMethod()
{
//Faz alguma coisa.
}
public void DoSomethingMore()
{
//Faz outra coisa.
}
}
C++
# include <iostream>
# include <vector>
using namespace std;
// 2. criando uma "interface" (Minimo demominador comum)
class Componente
{
public:
virtual void traverse() = 0;
};
class Folha: public Componente
{
// 1. Escalar classe
int valor;
public:
Folha(int val)
{
valor = val;
}
void traverse()
{
cout << valor << ' ';
}
};
class Composite: public Componente
{
// 1. classe Vetor
vetor < Componente * > filho; // 4. "conteiner" Acoplado à interface
public:
// 4. "conteiner" classe acoplado à interface
void add(Componente * ele)
{
filho.push_back(ele);
}
void traverse()
{
for (int i = 0; i < filho.size(); i++)
// 5. Polimorfismo para delegar ao filho
filho[i]->traverse();
}
};
int main()
{
Composite conteiners[4];
for (int i = 0; i < 4; i++)
for (int j = 0; j < 3; j++)
conteiners[i].add(new Folha(i *3+j));
for (i = 1; i < 4; i++)
conteiners[0].add(&(conteiners[i]));
for (i = 0; i < 4; i++)
{
conteiners[i].traverse();
cout << endl;
}
}
var Node = function (name) {
this.children = [];
this.name = name;
}
Node.prototype = {
add: function (child) {
this.children.push(child);
},
remove: function (child) {
var length = this.children.length;
for (var i = 0; i < length; i++) {
if (this.children[i] === child) {
this.children.splice(i, 1);
return;
}
}
},
getChild: function (i) {
return this.children[i];
},
hasChildren: function () {
return this.children.length > 0;
}
}
// recursively traverse a (sub)tree
function traverse(indent, node) {
log.add(Array(indent++).join("--") + node.name);
for (var i = 0, len = node.children.length; i < len; i++) {
traverse(indent, node.getChild(i));
}
}
// logging helper
var log = (function () {
var log = "";
return {
add: function (msg) { log += msg + "\n"; },
show: function () { alert(log); log = ""; }
}
})();
function run() {
var tree = new Node("root");
var left = new Node("left")
var right = new Node("right");
var leftleft = new Node("leftleft");
var leftright = new Node("leftright");
var rightleft = new Node("rightleft");
var rightright = new Node("rightright");
tree.add(left);
tree.add(right);
tree.remove(right); // note: remove
tree.add(right);
left.add(leftleft);
left.add(leftright);
right.add(rightleft);
right.add(rightright);
traverse(1, tree);
log.show();
}
Para implementar o padrão Composite, é necessário considerar vários aspectos, sendo eles:
O padrão Composite é bastante utilizado com o Iterator para percorrer a estrutura em forma de árvore oferecida pelo primeiro. Imaginemos que há uma classe abstrata Component com vários métodos e um deles é utilizado para imprimir toda estrutura. Esse método printar() é herdado tanto pela folha quanto pelo composite, portanto fazendo essa iteração é possível percorrer e imprimir todos os componentes de Component pois tanto a folha quanto o composite são do tipo Component e implementam suas própria versões do método printar().
public class Composite extends Component {
ArrayList<Component> components = new ArrayList<Component>();
String componentName;
// alguns métodos herdados por Component
public void printar(){
System.out.println("Componente :" + componentName);
Iterator iterator = components.iterator();
while(iterator.hasNext()){
Component component = (Component)iterator.next();
component.printar();
}
}
}
|título=
(ajuda)Seamless Wikipedia browsing. On steroids.
Every time you click a link to Wikipedia, Wiktionary or Wikiquote in your browser's search results, it will show the modern Wikiwand interface.
Wikiwand extension is a five stars, simple, with minimum permission required to keep your browsing private, safe and transparent.