COSC 3351 Software Design Design Patterns Structural Patterns (I) Spring 2008 Purpose Creational Structural Behavioral Scope Class Factory Method Adaptor(class) Interpreter Template Method Object Abstract Factory Adaptor(object) Chain of Responsibility Builder Bridge Command Prototype Composite Iterator Singleton Decorator Mediator Façade Flyweight Proxy Observer State Strategy Visitor Memento 1
Structural Patterns Deal with how classes and objects are composed to form larger structures Structural class patterns use inheritance to compose interfaces or implementations Structural object patterns describe ways how to compose objects realizing new functionality; mainly use composition Adapter Intent: convert the interface of a class into another interface a client expects. Adapter lets classes work together that couldn t work else because of incompatible interfaces Also known as Wrapper Applicability: Use the adapter pattern when You want to use an existing class and its interface does not match the one you need You want to create a reusable class that cooperates with unrelated or unforeseen classes 2
Structure of class adapter using multiple inheritance Client Target + Request() Adaptee + SpecificRequest() Adapter + Request() Adapter:: Request() { SpecificRequest(); Structure of object adapter using object inheritance Client Target + Request() Adaptee + SpecificRequest() Adapter + Request() Adapter:: Request() { adaptee->specificrequest(); 3
Participants Target: defines the domain specific interface that Clients use Client: collaborates with objects conforming to the Target interface Adaptee: defines an existing interface that needs adapting Adapter: adapts the interface of Adaptee to the Target interface Consequences Class adapter: Adapts Adaptee to a concret Adaptee class-> class adapter won t work when we want to adapt a class and all its subclasses Object adapter: Works with many adaptees Adaptee and all its subclasses Overriding Adaptee behavior requires subclassing adaptee and make Adapter refer to subclass 4
Two way adapters Adapters are not necessarily transparent to all clients, since the adapted object no longer confirms to adapted interface Two-way adapters make sure, that both Adaptee and Client can modify/manipulate the object Example Consider a drawing editor with support for lines, polygons, text etc. Interface for graphical objects are provided by an abstract Class called Shape Editor defines subclasses for each object, e.g. PolygonShape, LineShape etc. Subclass for text very complex -> would like to use an existing toolkit (TextView) Interfaces do not match 5
Class Adapter class Shape { public: Shape(); virtual void BoundingBox (Point& bottemleft, Point& topright) const; virtual Manipulator* CreateManipulator() const; class TextView { public: TextView(); void GetOrigin (Coord& x, Coord& y) const; void GetExtent (Coord& width, Coord& height) const; virtual bool IsEmpty(); class TextShape: public Shape, private TextView { public: TextShape(); virtual void BoundingBox(Point& bottemleft, Point& topright) const; virtual bool IsEmpty(); virtual Manipulator* CreateManipulator() const; Class Adapter void TextShape:: BoundingBox (Point& bottemleft, Point& topright) const { Coord bottom, left, width, height; GetOrigin(bottom, left); GetExtent(width, height); bottomleft = Point(bottom, left); topright = Point(bottom+height, left+width); bool TextShaoe:: IsEmpty() const { return TextView::IsEmpty(); // This function is not supported by TextView, so we have to // implement it ourselves Manipulator* TextShape:: CreateManipulator () const { return new TextManipulator(this); 6
Object Adapter class TextShape: public Shape { public: TextShape(TextView*); virtual void BoundingBox(Point& bottemleft, Point& topright) const; virtual bool IsEmpty(); virtual Manipulator* CreateManipulator() const; private: TextView* _text; TextShape:: TextShape (TextView* t) { _text = t; void TextShape:: BoundingBox (Point& bottemleft, Point& topright) const { Coord bottom, left, width, height; _text->getorigin(bottom, left); _text->getextent(width, height); bottomleft = Point(bottom, left); topright = Point(bottom+height, left+width); Bridge Intent: Decouple an abstraction from its implementation so that the two can vary independently Applicability: use the bridge pattern when You want to avoid permanent binding between abstraction and its implementation Both abstraction and implementation should be extensible by subclassing Changes in the implementation of an abstraction should have no impact on the clients 7
Structure Client Abstraction + Operation() Implementor + OperationImp() Refined Abstraction + Operation() ConcreteImplementor A + OperationImp() ConcreteImplementor B + OperationImp() imp->operationimp(); Participants Abstraction: defines the abstraction interface; maintains a reference to an object of type Implementor RefinedAbstraction: extends the interface defined by Abstraction Implementor: defines the interface for implementation classes. Please note, that this interface does not have to correspond exactly to the Abstraction s interface ConcreteImplementator: implements the Implementor interface 8
Example: portable Window abstraction Bridge Window WindowImp + DrawText() + DrawRect() + DevDrawText() + DevDrawLine() Icon Window Transient Window XWindowsImp PMWindowsImp + DrawBorder() + DrawCloseBox() + DevDrawText() + DevDrawLine() + DevDrawText() + DevDrawLine() imp->devdrawline(); imp->devdrawline(); imp->devdrawline(); imp->devdrawline(); Difference between Bridge and Adapter The Adapter pattern Is geared toward making unrelated classes work together It is usually applied to systems after they are designed The Bridge pattern Is used upfront in design to let abstractions and implementations vary independently 9
Composite Intent: Compose objects into tree structures to represent partwhole relationship The Composite patterns lets clients treat individual objects and composites uniformly Applicability: use the composite pattern when You want to represent part-whole hierarchies of objects You want clients to be able to ignore the difference between composition of objects and individual objects Structure Client Component + Operation() + AddComponent() + RemoveComponent() + GetChild(n) Leaf Composite + Operation() + Operation() + AddComponent() + RemoveComponent() + GetChild(n) 10
Participants Component: Declares the interface for objects in the composition Implements default behavior for the interface common to all classes Declares an interface for accessing and managing its child components (optional) defines an interface for accessing a component s parent in the recursive structure Leaf: defines behavior of primitive objects in the composition Composite: defines behavior for components having children Client: manipulates objects in the composition through the Component interface Implementation issues Explicit parent references Required if you might move up in the hierarchy, not down Simplifies deleting a component Declaring child operations Declared in the component interface: requires meaningful defaults for leafs Gives you transparency Costs you safety, since clients may try to do meaningless operations on leafs Declared in the composite interface: Gives you security Costs transparency 11
Implementation issues Should component interface contain the set of children? Putting the child pointer into the base class might incur a space penalty Child ordering If required, must be handled in the child access and management interface Caching: Can be introduced in the composite class to store information about the children, if you expect a large number of similar traversals Decorator Intent: attach additional responsibility to an object dynamically Applicability: use a Decorator To add responsibilities to individual objects dynamically and if you do not want to affect other objects For responsibilities that can be withdrawn When extensions by subclassing is impractical 12
Structure Component + Operation() ConcreteComponent Decorator + Operation() + Operation() Component->Operation() Concrete Decorator A + addedstate + Operation() Concrete Decorator B + Operation() + addedbehavior Participants Component: defines the interface for objects that can have responsibilities attached to them dynamically ConcreteComponent: defines an object to which additional responsibilities can be attached Decorator: maintains a reference to a Component object and defines interface that conforms to Component s interface ConcreteDecorator: adds responsibilities to a component 13
Example: using decorators in a graphics library class VisualComponent{ public: VisualComponent(); virtual void Draw(); virtual void Resize(); class Decorator : public VisualComponent { public: Decorator(VisualComponent*); virtual void Draw(); virtual void Resize(); private: VisualComponent* _component; void Decorator:: Draw () { _component->draw(); void Decorator:: Resize () { _component->resize(); Example: using decorators in a graphics library class class BorderDecorator:: public Decorator { public: BorderDecorator(VisualComponent*, int width); virtual void Draw(); private: void DrawBorder(int); int _width; void BorderDecorator:: Draw () { Decorator::Draw() DrawBorder(_width); Please note: from an identity point of view, a decorated component is not identical to the component itself You can not rely on object identity when using decorator 14