COSC 3351 Software Design
Design Patterns Structural Patterns (II)
Edgar Gabriel Spring 2008
Edgar Gabriel
Decorator
• Allows to add responsibilities to objects dynamically without subclassing • Objects are nested within another • Each Decorator object must conform to the interface of its component • Each Decorator object must forward messages to the main component
COSC 3351 – Software Design Edgar Gabriel
1 Facade
• Intent : Provide a unified interface to a set of interfaces in a subsystem. Facade defines a higher level interface that makes usage of the subsystem easier. • Applicability : Use the Facade pattern when – You want to provide a simple interface to a complex subsystem. A Façade can provide a simple default view of the subsystem that is good enough for most clients – There are many dependencies between clients and the implementation classes of an abstraction. A facade ‘decouples’ clients from the subsystem – You want to layer your subsystem
COSC 3351 – Software Design Edgar Gabriel
Structure of the facade pattern
Client
Facade
COSC 3351 – Software Design Edgar Gabriel
2 Example
• Programming environment that gives applications access to the compiler subsystem • Compiler subsystem consists of many classes such as – Scanner – Parser – ProgramNode – BytecodeStream – ProgramNodeBuilder • Most applications (clients) only want to utilize a default compile() method, hiding the complexity of the compiler
COSC 3351 – Software Design Edgar Gabriel
Example (II)
// The facade interface class Compiler { public: Compiler(); virtual void Compile (istream&, BytecodeStream&); }
void Compiler:: Compile (istream& input, BytecodeStream& output ) {
Scanner scanner(input); ProgramNodeBuilder builder; Parser parser;
parser.Parse (scanner, builder ); RISCCodeGenerator generator(output); ProgramNode *parseTree = builder.GetRootNode(); parseTree->Traverse(generator); }
COSC 3351 – Software Design Edgar Gabriel
3 Flyweight
• Intent : use sharing to support a large number of fine- grained objects efficiently • Applicability: use the flyweight patter when all of the following are true – An application uses a large number of objects – Storage costs are high because of the sheer quantity of objects – Most object state can be made extrinsic – Many groups of objects may be replaced by relatively few shared objects – The application does not depend on object identity. Since flyweight objects may be shared, identity tests will return true for conceptually distinct objects COSC 3351 – Software Design Edgar Gabriel
Structure
<
GetFlyweight(key) Operation(extrinsicState)
if (flyweight[key] exists) return existing flyweight; else { create new flyweight; add to pool of flyweights; return new flyweight; }
ConcreteFlyweight UnsharedConcreteFlyweight IntrinsicState allState Operation(extrinsicState) Operation(extrinsicState)
Client
COSC 3351 – Software Design Edgar Gabriel
4 Participants
• Flyweight : declares an interface through which flyweights can receive and act on extrinsic state • ConcreteFlyweight : implements the Flyweight interface and adds storage for intrinsic state. Object must be sharable, i.e. any state it stores must be independent of the ConcreteFlyweight object’s context. • FlyweightFactory : creates and manages flyweight objects • Client : maintains a reference to flyweights; computes or stores extrinsic state of flyweights • UnsharedConcreteFlyweight: implements the Flyweight interface. However, not all Flyweight subclasses need to be shared. The flyweight interface enables sharing, it doesn’t enforce it. COSC 3351 – Software Design Edgar Gabriel
Example
• Consider a document editor: typically, every item in a document (table, image etc.) is handled as an object • An editor can however not handle each character as an object, although it would make handling of the document simple – Too many objects for even small/medium documents – Run time behavior would be unacceptable • Solution using flyweight pattern: create a flyweight for each character of the ASCII set – Intrinsic state: character to be represented – Extrinsic state: font
COSC 3351 – Software Design Edgar Gabriel
5 Example (II)
<
Draw(Context) Intersects(Point, Context)
Row Character Column
Draw(Context) Draw(Context) Draw(Context) Intersects(Point, Context) Intersects(Point, Context) Intersects(Point, Context)
• Glyph: abstract Flyweight class • Character: ConcreteFlyweight • Row, Column: UnsharedConcreteFlyweight
COSC 3351 – Software Design Edgar Gabriel
class Glyph { public: virtual ~Glyph(); virtual void Draw (Window*, GlyphContext&); virtual void SetFont (Font*, GlyphContext&); virtual Font* GetFont (GlyphContext&); … } class Character : public Glyth { public: Character (char); virtual void Draw (Window*, GlyphContext&) private: char _charcode; } class GlyphContext { public: GlyphContext(); virtual void Next( int step=1); virtual void Insert (int quantity=1); virtual Font* GetFont(); virtual void SetFont(Font*, int span=1); private: int _index; Btree* _fonts; } COSC 3351 – Software Design Edgar Gabriel
6 • GlyphContext – Acts as a repository for the external state – Stores in _fonts the font currently used at a given position – Every Glyph ’s child iteration and manipulation must update the GlyphContext whenever used – GlyphContext::Next increments _index as traverses the clases • All subclasses of Glyph must implement Next so that it calls GlyphContext::Next at each point in traversal.
COSC 3351 – Software Design Edgar Gabriel
const int NCHARCODES = 128;
class GlyphFactory { public: GlyphFactory(); virtual ~GlyphFactory(); virtual Character* CreateCharacter(char); virtual Row* CreateRow(); virtual Column* CreateColumn (); … private: Character * _character[NCHARACTER]; }
GlyphFactory :: GlyphFactory() { for ( int i=0; I Character *GlyphFactory:: CreateCharacter (char c) { if (!_character[c] ) { _character[c] = new Character(c); } return _character[c]; } COSC 3351 – Software Design Edgar Gabriel 7 Row *GlyphFactory:: CreateRow() { return new Row; } Column *GlyphFactory:: CreateColumn() { return new Column; } • Summary: instead of having a separate character object for each character in the document, we have a reference to shared glyph objects. • External state (position, font) are stored outside of the shared flyweight objects. COSC 3351 – Software Design Edgar Gabriel Proxy • Intent: provide a placeholder or surrogate for another object to control access to it • Applicability: – A remote proxy provides a local representation for an object in a different address space – A virtual proxy creates expensive objects on demand – A protection proxy controls access to the original object – A smart reference is a replacement for a bare pointer that performs additional actions when an object is accessed, such as • Counting the number of references to a real object • Checking that the real object is locked to ensure, that no other object can change it COSC 3351 – Software Design Edgar Gabriel 8 Structure < Request() RealSubject Proxy Request() Request() … realSubject->Request(); … COSC 3351 – Software Design Edgar Gabriel Summary of Structural Patterns • Adapter: makes one interface conform to another, non- conformant interface • Bridge: separates an object’s abstraction from its implementation, such that you can vary both independently • Composite: describes how to build a class hierarchy made up of classes for two kinds of objects: primitives and composites • Proxy: acts as placeholder for another object • Flyweight: defines a structure for sharing objects • Decorator: describes how to add responsibility to objects without subclassing COSC 3351 – Software Design Edgar Gabriel 9 Summary of Structural Patterns (II) • There are only a small set of language mechanisms for structuring codes and objects: – Single and multiple inheritance for class-based patterns – Object composition for object patterns. COSC 3351 – Software Design Edgar Gabriel 10