Intent
- Compor objectos em estruturas de árvore para representar hierarquias inteiras. Composite permite aos clientes tratar objetos individuais e composições de objetos uniformemente.
- Composição recursiva
- “Diretórios contêm entradas, cada um dos quais poderia ser um diretório”
- 1-para-muitos “tem a” acima da hierarquia “é a”
Problema
Aplicação precisa manipular uma coleção hierárquica de objetos “primitivos “e “compostos”. Ter que consultar o “tipo” de cada objeto antes de tentar processá-lo não é desejável.
Discussão
Definir uma classe base abstrata (Componente) que especifique o comportamento que precisa ser exercido uniformemente em todos os objetos primitivos e compostos. Subclasse as classes Primitiva e Composta fora da classeComponente. Cada objeto Composto “se casa” apenas com o tipo abstrato Componente, pois ele administra seus “filhos”.
Utilize este padrão sempre que você tiver “compostos que contenham componentes, cada um dos quais poderia ser um composto”.
Métodos de gerenciamento de crianças deveriam ser definidos na classe Composto. Infelizmente, o desejo de tratar Primitivos e Compostos uniformemente requer que estes métodos sejam movidos para a classe abstrata Componente. Veja a seção “Opiniões “abaixo para uma discussão de “segurança” versus “transparência “questões.
Estrutura
Compostos que contenham Componentes, cada um dos quais poderia ser umComposto.
Menus que contenham itens de menu, cada um dos quais poderia ser um menu.
Gerenciadores de layout GUI de coluna baixa que contenham widgets, cada um dos quais poderia ser um gerenciador de layout GUI de coluna baixa.
Diretórios que contêm arquivos, cada um dos quais poderia ser um diretório.
Containers que contêm Elementos, cada um dos quais poderia ser um Container.
Exemplo
O Composite compõe objetos em estruturas de árvore e permite aos clientes tratar objetos individuais e composições uniformemente. Embora o exemplo seja abstrato, as expressões aritméticas são Composites. A expressão anaritmética consiste em um operando, um operador (+ – * /),e outro operando. O operando pode ser um número, ou uma outra expressão aritmética. Assim, 2 + 3 e (2 + 3) + (4 * 6) são expressões ambasvalidas.
Lista de verificação
- Certifique-se de que o seu problema é representar relações hierárquicas “inteiras”.
- Considere o heurístico, “Recipientes que contêm containees, cada um dos quais pode ser um recipiente”. Por exemplo, “Assemblies that contain components, each of which could be an assembly.” Divida seus conceitos de domínio em classes de contêineres e classes de contêineres.
- Crie uma interface de “menor denominador comum” que torne os contêineres e contêineres intercambiáveis. Ele deve especificar o comportamento que precisa ser exercitado uniformemente em todos os objetos containereee container.
- Todas as classes container e containee declaram uma relação “é uma “relação com a interface.
- Todas as classes container declaram uma relação de um para muitos “tem uma” relação com a interface.
- Classes container alavancam o polimorfismo para delegar aos objetos containeree.
- Métodos de gerenciamento de crianças devem ser normalmente definidos na classe Composite. Infelizmente, o desejo de tratar objetos Leaf e Composite uniformemente pode exigir que estes métodos sejam promovidos para a classe Componente abstrato. Veja o Gang ofFour para uma discussão dessas trocas de “segurança” versus “transparência”.
Regras de polegar
- Composto e Decorador têm diagramas de estrutura similares, refletindo o fato de que ambos dependem de composição recursiva para organizar um número aberto de objetos.
- Composto pode ser atravessado com Iterator. O visitante pode aplicar uma operação sobre um Composite. O Composite pode usar Chain ofResponsibility para permitir que os componentes acessem propriedades globais através de seu parente. Também pode usar o Decorator para sobrepor essas propriedades em partes da composição. Ele poderia usar o Observador para ligar uma estrutura de um objeto a outro e o Estado para permitir que um componente altere seu comportamento em relação às mudanças de estado.
- Composto pode permitir que você componha um Mediador a partir de peças menores através da composiçãorecursiva.
- Decorador é projetado para permitir que você adicione responsabilidades aos objetos sem subclassificação. O foco do Composite não é o embelezamento, mas a representação. Consequentemente, Composite e Decorator são frequentemente usados em conjunto.
- O peso da mosca é frequentemente combinado com Composite para implementar os nós de folhas partilhados.
Opiniões
O objectivo do padrão Composite é que o Composite pode apostar atomicamente, tal como uma folha. Se você quiser fornecer o protocolo de anIterator, tudo bem, mas eu acho que isso está fora do padrão. No coração deste padrão está a capacidade de um cliente realizar operações de toperform em um objeto sem precisar saber que existem muitos objetos dentro dele.
Ser capaz de tratar uma coleção heterogênea de objetos atomicamente (ou transparentemente) requer que a interface “gestão infantil” seja definida na raiz da hierarquia da classe Composite (a classe abstractComponent). No entanto, esta escolha custa-lhe segurança, porque os clientes podem tentar fazer coisas sem sentido como adicionar e remover objectos de objectos de folha. Por outro lado, se você “desenha por segurança”, a interface de gerenciamento da criança é declarada na classe Composite, e você perde transparência porque folhas e Composites agora têm interfaces diferentes.
Aplicações do padrão Composite geralmente não têm a interface para gerenciar os componentes na interface Component, mas na interface Composite. As implementações em C++ tendem a colocá-lo na interface do Componente. Este é um fato extremamente interessante, e um que eu costumo ponderar. Eu posso oferecer teorias para explicar isso, mas ninguém sabe com certeza porque é verdade.
As minhas classes de Componentes não sabem que Composites existe. Elas fornecem ajuda para navegar em Composites, nem qualquer ajuda para alterar os componentes de um Composite. Isto porque eu gostaria que a classe base (e todas as suas derivadas) fossem reutilizáveis em contextos que não exigem Composites. Quando me é dado um ponteiro da classe base, se eu precisar absolutamente saber se é ou não um Composite, eu usarei dynamic_cast
para descobrir isso. Nos casos em que dynamic_cast
é muito barato, usarei um Visitante.
Lei Comum: “se eu empurrar a interface Composite para baixo na classeComposite, como vou enumerar (ou seja, atravessar) uma estrutura complexa?” Minha resposta é que quando eu tenho comportamentos que se aplicam a hierarquias como a apresentada no padrão Composite, uso tipicamente o Visitor, então a enumeração não é um problema – o Visitor sabe em cada caso, exatamente com que tipo de objeto ele está lidando. OVisitor não precisa de cada objeto para fornecer uma interface de enumeração.
Composto não o obriga a tratar todos os Componentes como Compostos. Itmerely lhe diz para colocar todas as operações que você quer tratar “uniformemente” na classe Componente. Se adicionar, remover e operações similares não podem, ou não devem, ser tratadas uniformemente, então não as coloque na classe Base de Componentes. Lembre-se, a propósito, que o diagrama de estrutura de cada padrão não define o padrão; ele meramente descreve o que, em nossa experiência, é uma realização comum. Justbecause O diagrama de estrutura do Composite mostra operações de gestão infantil na classe base Component não significa que todas as implementações do padrão devem fazer o mesmo.
Suporte o nosso site gratuito e seja dono do livro electrónico!
- 22 padrões de design e 8 princípios explicados em profundidade
- 406 páginas bem estruturadas, fáceis de ler e sem jargões
- 228 ilustrações e diagramas claros e úteis
- Um arquivo com exemplos de código em 4 idiomas
- Todos os dispositivos suportados: Formatos EPUB/MOBI/PDF
Saiba mais…