design patterns estudo de caso: um editor de documentos
TRANSCRIPT
Design Patterns
Estudo de Caso:
um editor de documentos
Motivação
Será apresentado o uso de design patterns no projeto de um editor WYSIWYG;
O estudo de caso se concentrará na estrutura do documento manipulado pelo editor.
Estrutura do documento
Um documento é um conjunto de elementos gráficos, tais como caracteres, linhas polígonos e outras formas;
Estas subestruturas devem ser manipuladas diretamente. Por exemplo, um diagrama deve ser tratado como uma unidade e não como uma coleção de primitivas gráficas básicas;
Os elementos devem ser tratados de forma uniforme.
Estrutura do documento
Pode ser representada por meio de composição recursiva;
Existirão então classes atômicas e classes recursivas.
Estrutura do documentoGrafico
Caracter Retângulo Linha
Draw(Window)Intersects(Point)Insert(Glyph, int)...
Draw(Window w)Intersects(Point p)...
char c
Draw(...)Intersects(...)...
Draw(Window w)Intersects(Point p)Insert(Grafico g, int i)...
w->DrawCharacter(c)
Return true if point pintersects this character
Insert g intochildren at position i
children
For all c in children if c->Intersects(p) return true
Estrutura do documento: Gráfico
É uma classe abstrata para todos os objetos gráficos que aparecem na estrutura do documento;
As subclasses definem elementos gráficos primitivos (ex: caracter, retângulo, etc.) e elementos estruturados (ex: linha);
São necessárias operações para inserir, remover e acessar os filhos de um gráfico.
O Pattern Composite
Para representar a estrutura do documento, foi utilizado o padrão estrutural composite;
Este padrão pode ser utilizado para representar qualquer estrutura hierárquica potencialmente complexa.
O Padrão Composite
Objetivo– Compõe objetos em estruturas de árvore para
representar hierarquias do tipo todo-parte. Permite que os clientes tratem objetos individuais e composições de maneira uniforme.
O Pattern Composite
Motivação– O problema do editor apresentado
anteriormente.– Um objeto típico seria:
aLine
aLineaLine
aRetânguloaLineaChar
aRetângulo
O Pattern Composite
Aplicabilidade– Use este padrão quando:
» precisar representar hierarquias do tipo todo-parte;
» quiser que os clientes ignorem as diferenças entre as composições e os objetos atômicos. Os clientes irão tratar todos os objetos da estrutura de maneira uniforme.
O Pattern Composite
Leaf
Operation()Add(Component)Remove(Component)GetChild(int)
Operation()
children
Client
CompositeOperation()Add(Component)Remove(Component)GetChild(int)
Component
For all g in children g.Operation();
Estrutura
O Pattern Composite
Participantes– Component
» declara a interface dos objetos na composição;
» implementa comportamento “default” para a interface comum a todas as classes;
» declara a interface para acessar e manipular os componentes “filhos”;
» opcionalmente, define a interface para acessar o “pai” de um componente na estrutura recursiva.
O Pattern Composite
Participantes (cont.)– Leaf (folha)
» representa objetos atômicos na composição. Uma folha não tem “filhos”;
» define o comportamento para objetos primitivos na composição.
O Pattern Composite
Participantes– Composite
» define o comportamento para componentes que têm “filhos”;
» armazena os “filhos”;» implementa operações relacionadas aos filhos na
interface do componente;
– Client» manipula objetos na composição através da interface do
componente.
O Pattern Composite
Colaborações– Clientes usam a interface das classes componentes
para interagir com os objetos na estrutura de composição. Se o recipiente de uma mensagem é uma folha, a solicitação é manipulada diretamente. Se o recipiente é um “Composite”, a solicitação é enviada para os seus filhos, e possivelmente, outras operações serão executadas antes e/ou depois da mensagem ser “forwarded”.
O Pattern Composite
Conseqüências– define hierarquias de classes consistindo de objetos primitivos e compostos.
Objetos primitivos podem ser combinados de forma a criar objetos compostos mais complexos, de forma recursiva. Em todo lugar onde o cliente espera por um objeto primitivo, ele pode receber um objeto composto;
– faz com que o cliente se torne mais simples. Clientes podem tratar estruturas compostas e objetos individuais de maneira uniforme. Clientes normalmente não sabem (e não devem se importar) se estão manipulando uma folha ou um componente composto. Isto simplifica o código do cliente, porque evita ter que escrever comandos do tipo “tag-and-case” sobre as classes que definem a composição;
– torna mais fácil a adição de novos componentes. Clientes não necessitam ser alterados quando novos componentes são inseridos na estrutura composta.
O Pattern Composite
Implementação (algumas considerações)– Referências explícitas ao pai: manter referências dos componentes filhos
para os componentes pais pode simplificar o caminhamento e o gerenciamento de uma estrutura composta. A referência ao pai simplifica o movimento para cima em uma estrutura e a remoção de um componente.
– O local correto para definir a referência ao pai é na classe Component. Leaf e Composite podem então herdar a referência e a operação que a manipula.
– Com a referência ao pai, é essencial manter o invariante de que todos os filhos de uma composição têm como pai a composição que os tem como filhos.
O Pattern Composite
Implementação (cont.)– Qual a melhor estrutura para armazenar
componentes? Os componentes filhos podem ser armazenados em listas ligadas, árvores, arrays ou tabelas hash. A escolha depende da eficiência desejada.
O Pattern Composite
Exemplo de Código– Equipamentos tais como computadores e
sistemas de som são freqüentemente organizados em estruturas todo-parte. Por exemplo, o chassis pode conter o drive e as placas, o gabinete pode conter o chassis, etc. Estas estruturas podem ser naturalmente modeladas usando o pattern Composite.
O Pattern Composite
Exemplo de Código (cont.)– A classe Equipement define uma interface comum a todos os equipamentos na hierarquia todo-parte.
class Equipement {
public:
virtual ~Equipement();
const char* Name() {return _name;}
virtual Watt Power();
virtual Currency NetPrice();
virtual Currency DiscountPrice();
virtual void Add(Equipement)*);
virtual void Remove(Equipement*);
virtual Iterator<Equipement*>* CreateIterator();
protected:
Equipement(const char*);
private:
const char* _name;
}
O Pattern Composite
Exemplo de Código (cont.)– Equipement declara operações que retornam
atributos de uma parte de um equipamento, tal como o seu consumo de energia e o custo. Subclasses implementam estas operações para tipos específicos de equipamento. Equipement também declara uma operação CreateIterator que retorna um Iterator para acessar suas partes.
O Pattern Composite
Exemplo de Código (cont.)– Subclasses de Equipement podem incluir classes
do tipo Leaf que representam drives de disco, circuitos integrados e switches.class FloppyDisk: public Equipement {
public:
FloppyDisk(const char*);
virtual ~FloppyDisk();
virtual Watt Power();
virtual Currency NetPrice();
virtual Currency DiscountPrice();
};
O Pattern Composite
Exemplo de Código (cont.)– CompositeEquipement é a classe base para equipamentos que contêm outros
equipamentos. Ela também é uma subclasse de Equipement.
class CompositeEquipement: Public Equipement {
public:
virtual ~CompositeEquipement();
virtual Watt Power();
virtual Currency NetPrice();
virtual Currency DiscountPrice();
virtual void Add(Equipement*);
virtual void Remove(Equipement*);
virtual Iterator<Equipement*>* CreateIterator();
protected:
CompositeEquipement(const char*);
private:
List<Equipement> _equipement;
};
O Pattern Composite
Exemplo de Código (cont.)– CompositeEquipement define as operações para
acessar e manipular subequipamentos. As operações Add e Remove inserem e deletam equipamentos da lista de equipamentos armazenada no atributo _equipement. A operação CreateIterator retorna um Iterator (especificamente uma instância de ListIterator) que será usado para navegar na lista de equipamentos.
O Pattern Composite
Exemplo de Código (cont.)– A implementação default da operação NetPrice pode
usar CreateIterator para somar os preços líquidos de cada subequipamento.
Currency CompositeEquipement::NetPrice() {
Iterator<Equipement*>* i = CreateIterator();
for (i->First(); !i->IsDone(); i->Next()) {
total += i->CurrentItem()->NetPrice();
}
delete i;
return total;
}
O Pattern Composite
Exemplo de Código (cont.)– O componente chassis pode então ser definido
como uma subclasse de CompositeEquipement.class Chassis: public CompositeEquipement {
public:
Chassis(const char*);
virtual ~Chassis();
virtual Watt Power();
virtual Currency NetPrice();
virtual Currency DiscountPrice();
};
O Pattern Composite
Exemplo de Código (cont.)– Outros equipamentos, tais como Gabinete,
podem ser definidos de forma similar. Os equipamentos podem ser então montados da seguinte forma:Gabinete* gabinete = new Gabinete(“PC Cabinet”);
Chassis* chassis = new Chassis(“PC Chassis”);
gabinete->Add(chassis);
chassis->Add(new FloppyDisk(“3.5in Floppy”));
cout << “O preço liquido é “<< chassis->NetPrice();
O Pattern Composite
Usos Conhecidos– Exemplos do pattern Composite podem ser
encontrados em quase todos os sistemas orientados a objetos.
O Pattern Composite
Patterns Relacionados– Iterator pode ser usado para navegar através
dos componentes;– etc.