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 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

<> Flyweightfactory Flyweight

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)

<> Glyph

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

<> Subject

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