1 Padrões: Composite (p. 163) • Objetivo: compor objetos em estruturas de árvores para representar relações de parte/todo. “Composite” permite tratar objetos individuais e composições de maneira uniforme Motivação • aplicações gráficas como editores de figuras permitem ao usuário criar diagramas complexos a partir de componentes simples – implementação simplista pode definir classes para primitivas gráficas como texto e linhas e outras classes para conterem estas classes básicas – problema: o código que usa estas classes precisa tratar diferentemente as classes básicas e classes que as contem. • “composite” descreve como usar composição recursiva para evitar esta distinção 2 3 Motivação (2): figura 4 Aplicabilidade • quando se quer hierarquias de objetos que se relacionam como parte/todo • quando se quer que “clientes” ignorem a diferença entre composição de objetos e objetos individuais. 5 Estrutura (fig.) Participantes • Componente: – define a interface para os objetos da composição – implementa comportamento “default” para interface comum das classes – declara interface para acessar e manipular seus componentes subordinados – (opcional) define uma interface para acessar o componente “pai” na estrutura recursiva • Folha: – representa objetos atômicos – define o comportamento dos objetos básicos do sistema 6 7 Participantes (cont.) • Composite – define o comportamento dos componentes que tem subordinados – guarda referências para os subordinados – implementa operações associadas aos elementos base na classe Componente • Cliente – manipula objetos do sistema utilizando a interface de Component 8 Colaborações • clientes utilizam interface de Component para interagir com estrutura • se recipiente de uma mensagem é Leaf a requisição é tratada diretamente • se recipiente é Composite então geralmente ele retransmite mensagens para seus componentes 9 Conseqüências • define hierarquia de classes que consistem de objetos primitivos (Leaf) e objetos compostos (Composite). Composição de objetos em objetos mais complexos é recursiva • simplifica a estrutura do cliente • facilita a adição de novos componentes no sistema • pode fazer a arquitetura do sistema geral demais – facilitar adição de componentes dificulta impor restrições aos elementos de um Composite. Com composite não se pode impor a restrição com estrutura de tipos, mas apenas com verificações em tempo de execução Implementação • referências explícitas a “pais” – simplifica percorrer hierarquia e simplifica manutenção da estrutura (movimentação vertical e eliminação) – simplifica manutenção do padrão Cadeia de Responsabilidades (“Chain of Responsibility) – lugar usual: classe Componente – necessário manter consistência: mudar referência a “pai” só através das operações add e remove de Composite • compartilhando componentes – possibilidade é múltiplos “pais” mas introduz ambigüidades na medida que requisições são propagadas na estrutura – utilizar padrão Flyweight (p. 195) 10 11 Implementação (2) • maximizando a interface de Component – para permitir que clientes não precisem se concientizar da estrutura de componentes – providenciar implementações “default” – conflito com princípio que cada classe deve definir apenas operações que fazem sentido para ela (e.g. op. em Component não faz sentido em Leaf) • usar criatividade: Leaf é como um Component sem filhos (default é não voltar filhos, Composite modifica) Implementação (3) • declaração das operações de manutenção de descendentes – Composite implementa add e remove – quem delclara? • em Component ganha-se transparência perde-se segurança (clientes podem pedir operações sem sentido com adicionar dependentes em Leaf) • em Composite ganha-se segurança: operações ilegais podem ser detectadas durante compilação, perde-se transparência – Transparência em C++ – GetComposite (default é nil pointer) – Add, Remove (default em Component) 12 Implementação (4) 13 • Component deve implementar uma lista de Components? - custa espaço • Ordenação de descendentes diretos – padrão Iterator (pg. 257) • Caches: Composite pode manter caches para aumentar eficiência (e.g. “bounding box”) – mudanças no componente invalidam as caches de seus ascendentes (melhor quando componentes conhecem ascendente direto) • Quem deve remover componentes? – sem coleta de lixo: Composite – exceção: quando Leafs são imutáveis e compartilhados • Qual a melhor estrutura para guardar componentes? – depende.... Utilizações • Interfaces de usuário – View em Smalltalk MVC – quase todas os sistemas para desenvolver interfaces de usuário (ET++, InterViews) • Compiladores: – “RTL Smalltalk compiler framework” • RTLExpression • RegisterTranfer • Finanças: portfolio agrega “assets” • Padrão Command (pg. 233) 14 Padrões Relacionados • Chain of Responsibility – utiliza a ligação pai-filho • Decorator – usado em conjunto • Flyweight – permite o compartilhamento de componentes • Iterator – pode ser usado para enumeração de Composite • Visitor – concentra operações e comportamento que de outra maneira seriam distribuídas entre as classes Composite e Leaf 15