Professional Documents
Culture Documents
Basic Design Patterns: 2. Designing A Document Editor
Basic Design Patterns: 2. Designing A Document Editor
Formatting
User Interface
User Operations
Spelling Checking & Hyphenation
Document Structure
text line chars table image ...
paragraph
column
page
Document Structure
The internal representation should support:
Maintaining the documents physical structure, that is, the arrangement of text and graphics into lines, columns, tables, etc.
Generating and presenting the document visually Mapping positions on the display to elements in the internal representation
Document Structure
Constraints:
Glyph
children
Polygon
return true if p intersects this character
draw(...) intersects(...)
Recursive Composition
Composite Pattern
Recursive composition is good for more than just documents. It can be used to represent any potentially complex, hierarchical structure. The Composite pattern captures the essence of recursive composition in object-oriented terms.
What objects are responsible for carrying out different formatting policies?
How do these policies interact with the documents internal representation?
well define a Compositor class for objects that can encapsulate a formatting algorithm the glyphs it formats are the children of a special Glyph subclass called Composition
Strategy
compositor
composition
Glyph::insert(g, i) compositor.compose()
SimpleCompositor compose()
ArrayCompositor compose()
TeXCompositor compose()
Strategy Pattern
Encapsulating an algorithm in an object is the intent of the Strategy pattern. The key participants in the pattern are strategy objects and the context in which they operate. Compositors are strategies; they encapsulate different formatting algorithms. A Composition is the context for a Compositor strategy.
Using inheritance to do such extension precludes rearranging embellishments at runtime. An equally serious problem, is the explosion of classes that can result from an inheritancebased approach.
Composition
BorderedCompsosition
ScrollableComposition
Composition
BorderedCompsosition
ScrollableComposition
BorderedScrollableComposition
User Interface
Object composition offers a potentially more workable and flexible extension mechanism:
Since we know were embellishing an existing glyph, we could make the embellishment itself an object (class Border f.i.)
Glyph and Border: the next step is to decide who composes whom
If we put the Border in the Glyph then we must make modifications to all Glyph subclasses to make them aware of the border
User Interface
All this lead us to the concept of transparent enclosure, which combines the notions of (1) single child (or single-component) composition, and (2) compatible interfaces
Clients generally cant tell whether theyre dealing with the component or its enclosure: the enclosure delegates all its operations to its component and augments the components behaviour by doing work of its own (before or after) delegating an operation.
Monoglyph
Glyph draw(Window)
MonoGlyph draw(Window)
component
Scroller draw(Window)
Decorator Pattern
The Decorator pattern captures class and object relationships that support embellishment by transparent enclosure. In the Decorator pattern, embellishment referes to anything that adds responsibilities to an object.
Factory Hierarchy
Glyph ...
Product Hierarchy
Menu popup() ...
WindowsButton
WindowsMenu
pressed() ...
popup() ...
graphics
virtual void drawLine() virtual void drawRect() virtual void drawText() ...
glyph
FrameWindow
IconWindow iconify()
DialogWindow lower()
owner
owner->lower()
FrameWindow
DialogWindow
XWindowImp deviceRaise()
Bridge Pattern
The intent behind Bridge is to allow separate class hierarchies to work together even as they evolve independently.
The Bridge pattern lets us maintain and enhance our logical window abstractions without touching window systemdependent code, and vice versa.
Command execute()
Command Hierarchy
SaveCommand execute()
pop up a dialog box that lets the user name the document and then save the document
Glyph
MenuItemCommand
MenuItem clicked()
command
Command
execute()
command->execute()
Command Pattern
The Command pattern describes how to encapsulate a request.
It prescribes a uniform interface for issuing requests that lets you configure clients to handle different requests. The interface shields clients from the requests implementation.
We also want to avoid wiring this functionality into the document structure.
void first( Traversal ) void next() boolean isDone() Glyph current() void insert( Glyph )
iterators
1..*
glyph->draw( this )
1..*
return true
root
Glyph
... createIterator()
return new NullIterator
Iterator Pattern
The Iterator pattern captures the techniques for supporting access and traversal over object structures.
Its applicable not only to composite structures but to collections as well.
Iterator Pattern
The Iterator pattern abstracts the traversal algorithm and shields clients from the internal structure of the objects (containers) they traverse.
It illustrates once more how encapsulating the concept that varies helps us gain flexibility and reusability.
}
(polymorphism)
Now adding a new analysis requires just defining a new subclass of Visitor: we dont have to touch any of the Glyph classes.
Visitor Pattern
The Visitor class and its subclasses described are the key particpants in the pattern.
Visitor lets you define a new operation without changing the classes of the elements on which it operates.
Summary
1. Composite to represent the documents physical structure 2. Strategy to allow different formatting algorithms
Summary
5. Bridge to allow multiple windowing platforms 6. Command for undoable user operations 7. Iterator for accessing and traversing object structures 8. Visitor for allowing an open-ended number of analytical capabilities without complicating the documents structure implementation