Presentation is loading. Please wait.

Presentation is loading. Please wait.

Design Patterns David Talby. This Lecture n Representing Data Structures u Composite, Flyweight, Decorator n Traversing Data Structures u Iterator, Visitor.

Similar presentations


Presentation on theme: "Design Patterns David Talby. This Lecture n Representing Data Structures u Composite, Flyweight, Decorator n Traversing Data Structures u Iterator, Visitor."— Presentation transcript:

1 Design Patterns David Talby

2 This Lecture n Representing Data Structures u Composite, Flyweight, Decorator n Traversing Data Structures u Iterator, Visitor

3 A Word Processor n Pages, Columns, Lines, Letters, Symbols, Tables, Images,... n Font and style settings per letter n Frames, Shadows, Background, Hyperlink attached to anything n Unlimited hierarchy: Tables with several Paragraphs containing hyper-linked images inside tables n Should be open for additions...

4 A Data Structure n First, a uniform interface for simple things that live in a document: class Glyph { void draw(Window *w) = 0; void move(double x, double y) = 0; bool intersects(Point *p) = 0; void insert(Glyph *g, int i) = 0; void remove(int i) = 0; Glyph* child(int i) = 0; Glyph* parent() = 0; }

5 Composite Documents

6 At Runtime n Unlimited Hierarchy problem solved n Dynamic selection of composites n Open for additions

7 2. Flyweight n Use sharing to support a large number of small objects efficiently n For example, if every character holds font and style data, a long letter will require huge memory n Even though most letters use the same font and style n How do we make it practical to keep each character as an object?

8 The Requirements n Reduce the memory demands of having an object per character n Keep the flexibility to customize each character differently

9 The Solution n Intrinsic state = worth sharing n Extrinsic state = not worth sharing

10 The Solution II n Put extrinsic state in a class: class CharacterContext { Font* font; bool isItalic, isBold,...; int size; int asciiCode; // many others… draw(int x, int y) {... } // other operational methods }

11 The Solution III n Original class holds rest of state: class Character : public Glyph { CharacterContext *cc; int x, y; draw() { cc->draw(x,y); }

12 The Solution IV n A factory manages the shared pool n It adds the object to the pool if it doesn’t exists, and returns it n Here’s Character ’s constructor: Character(int x, int y, Font *f, …) { this->x = x; this->y = y; this->cc = factory.createCharacter(f, …); }

13 The UML

14 The Fine Print n There’s a lot of tradeoff in what is defined as “extrinsic” n Shared pool is usually a hash table n Use reference counting to collect unused flyweights n Don’t rely on object identity u Different objects will seem equal

15 Known Uses n Word processors u Average 1 flyweight per 400 letters n Widgets u All data except location, value n Strategy design pattern n State design pattern

16 3. Decorator n Attach additional features to an objects dynamically n For example, many features can be added to any glyph in a document u Background, Note, Hyperlink, Shading, Borders, …

17 The Requirements n We can freely combine features u An image can have a background, a border, a hyper-link and a note n Features are added and removed dynamically n Can’t afford a class per combination n Should be easy to add new features u Don’t put it all in Glyph

18 The Solution n Meet Decorator, a class for adding responsibilities to another glyph: class Decorator : public Glyph { void draw() { component->draw(); } // same for other features private: Glyph *component; }

19 The Solution II n Define concrete decorators: class BackgroundDecorator : public Decorator { void draw() { drawBackground(); glyph->draw(); }

20 The Solution III n Many decorators can be added and removed dynamically: n Behavior can be added before and after calling the component n Efficient in space n Order of decoration can matter

21 The UML

22 The Fine Print n The Decorator class can be omitted if there’s only one decorator or Glyph is very simple n The Glyph class should be lightweight and not store data

23 Known Uses n Embellishing Document u Background, Border, Note,... n Communication Streams u Encrypted, Buffered, Compressed

24 Data Structure Summary n Patterns work nicely together u Composite, Decorator, Flyweight don’t interfere n Data structures are not layered u Instead, clients work on a Glyph interface hiding structures of unknown, dynamic complexity

25 Saving and Loading n Each Glyph should have “deep” read() and write() methods n Save to disk / Send over network by simply writing the root Glyph object of a document n All optimizations saved as well! n Also works on subtrees n Little coding

26 Cut, Copy, Paste n Cut = Detach a subtree n Copy = Clone a subtree n Paste = Attach a subtree n Also works on composite glyphs n Glyphs should hold a reference to parents for the cut operations n Cloning of a flyweight should only increase its reference count!

27 4. Iterator n Traverse a data structure without exposing its representation n An extremely common pattern n For example, a list should support forward and backward traversals u Certainly not by exposing its internal data structure n Adding traversal methods to List ’s interface is a bad idea

28 The Requirements n Traversal operations should be separate from List ’s interface n Allow several ongoing traversals on the same container n Reuse: it should be possible to write algorithms such as findItem that work on any kind of list

29 The Solution n Define an abstract iterator class: class Iterator { void first() = 0; void next() = 0; bool isDone() = 0; G* item() = 0; }

30 The Solution II n Each data structure implementation will also implement an iterator class: u ListIterator u HashTableIterator u FileIterator u StringIterator n Each data structure can offer more than one iterator: u Forward and backward iterators u Preorder, inorder, postorder

31 The Solution III n For example: class BackwardArrayIterator : public Iterator { Array *container; int pos; public: BackwardArrayIterator(Array *a) { container = a; first(); } next() { --pos; } // other methods easy }

32 The Solution IV n A data structure’s interface should return iterators on itself: class List { Iterator * getForwardIterator() { return new ListForwardIterator(this); } Iterator * getBackwardIterator () // similarly } n Now every LinkedList object can have many active iterators

33 The Solution V n Writing functions for containers: void print(Iterator * it) { for (it->first(); !it->isOver(); it->next()) cout item(); } n Using them: print(myList->getBackwardIterator()); print(myTable->getColumnItr(“Age”)); print(myTree->getPostOrderIterator());

34 The Solution VI n Generic algorithms can be written: G* findItem(Iterator * it, G *element) { while (!it->isOver()) { if (it->item() == element) return element; it->next(); } return NULL; }

35 The Requirements II n Some iterators are generic: u Traverse every n’th item u Traverse items that pass a filter u Traverse only first n items u Traverse a computed view of items n Such iterators should be coded once n It should be easy to combine such iterators and add new ones n Their use should be transparent

36 The Solution n Use the Decorator design pattern n For example, FilteredIterator receives another iterator and the filtering function in its constructor n It delegates all calls to its internal iterator except first() and next(): void next() { do it->next() while (!filter(it->item() && !it->isOver()); }

37 The Solution II n It is then easy to combine such generic iterators n Print square roots of the first 100 positive elements in a list: print(new LimitedIterator(100, new ComputedIterator(sqrt, new FilteredIterator(positive, list->getForwardIterator())))); n Adding an abstract DecoratorIterator reduces code size if many exist

38 The UML

39 The Fine Print n Everything is a container u Character strings u Files, both text and records u Socket streams over the net u The result of a database query u The bits of an integer u Stream of random or prime numbers n This allows reusing the print, find and other algorithms for all of these

40 The Fine Print II n Iterators may have privileged access u They can encapsulate security rights n Kinds of abstract iterators u Direct access iterators u Access the previous item n Robustness issues u Is the iterator valid after insertions or removals from the container? n Iterators and the Composite pattern

41 Known Uses n All major standard libraries of popular programming languages u STL for C++ u The Java Collections Framework n New libraries for file, network and database access in C++ conform to STL’s iterators as well

42 5. Visitor n Separate complex algorithms on a complex data structure from the structure’s representation n For example, a document is a composite structure involved in many complex operations u Spell check, grammar check, hyphenation, auto-format, … n How do we avoid cluttering Glyph subclasses with all this code?

43 The Requirements n Encapsulate complex algorithms and their data in one place n Outside the data structure n Easily support different behavior for every kind of Glyph n Easily add new tools

44 The Solution n Say hello to class Visitor : class Visitor { public: void visitImage(Image *i) { } void visitRow(Row *r) { } void visitTable(Table *t) { } // so on for every Glyph type } n Every tool is a subclass: class SpellChecker : public Visitor

45 The Solution II n Add to Glyph ’s interface the ability to accept visitors: void accept(Visitor *v) = 0; n Every glyph subclass accepts a visitor by an appropriate callback: class Image : public Glyph { void accept(Visitor *v) { v->visitImage(this); } n This way the visitor is activated for the right kind of glyph, with its data

46 The Solution III n Initiating a spell check (one option): u Create a SpellChecker object  root->accept(sc); n Graphic non-text glyphs will just ignore the visit u This is why Visitor includes default empty method implementations n Composite glyphs also do nothing u They can forward the visit to children. This can be coded once in CompositeGlyph

47 The Solution IV n Easy to add operations u Word count on characters u Filters such as sharpen on images u Page layout changes on pages n Works on any glyph u In particular, a dynamic selection as long as it’s a composite glyph n Adding a tool does not require recompilation of Glyph hierarchy

48 The UML

49 The Fine Print n The big problem: adding new Glyph subclasses is hard u Requires small addition to Visitor, and recompilation of all its subclasses n How do we traverse the structure? u Using an iterator u From inside the accept() code u From inside the visitxxx() code n Visitors are really just a workaround due to the lack of double dispatch

50 Known Uses n Document Editors u Spell Check, Auto-Format, … n Photo Editors u Filters & Effects n Compilers u Code production, pretty printing, tests, metrics and optimizations on the syntax tree

51 Summary n Pattern of patterns u Encapsulate the varying aspect u Interfaces u Inheritance describes variants u Composition allows a dynamic choice between variants n Design patterns are old, well known and thoroughly tested ideas u Over twenty years!


Download ppt "Design Patterns David Talby. This Lecture n Representing Data Structures u Composite, Flyweight, Decorator n Traversing Data Structures u Iterator, Visitor."

Similar presentations


Ads by Google