12
Structural Patterns Chapter 4 – Page 1 Stru ctur al Patt erns Design patterns that describe how classes and objects can be combined to form larger structur es Adapter Intent: Convert the programming interface of one class into that of another so the two classes can work together in one program Bridge Intent: Separate the interface of a class from its implementat ion so that either can be varied independent ly Composit e Intent: Develop a system in which a component may be an individual object or a collection of objects Decorato r Intent: Modify the behavior of individual objects without creating a new derived class Façade Intent: Reduce the complexity of elaborate subsystems by providing a simplified interface to them Flyweigh t Intent: Reduce the number of similar classes by sharing their commonality and passing their differences as parameters Proxy Intent: Represent a complex object with a simpler one, thereby postponing the instantiati on of the complex object until it is truly needed

Structural Patterns

  • Upload
    reuben

  • View
    35

  • Download
    0

Embed Size (px)

DESCRIPTION

Structural Patterns. Chapter 4 – Page 55. Structural Pattern: Adapter. Chapter 4 – Page 56. When the client expects to interact with a class in a particular manner, it is sometimes necessary to “adapt” the interface of the class to accommodate those expectations. - PowerPoint PPT Presentation

Citation preview

Page 1: Structural Patterns

Structural Patterns Chapter 4 – Page 1

Structural

Patterns

Design patterns

that describe

how classes and objects

can be combined

to form larger

structures

AdapterIntent: Convert

the programming

interface of one class into that of another so the two classes can

work together in one program

BridgeIntent: Separate the interface of a class from its

implementation so that either can be varied

independently

CompositeIntent: Develop

a system in which a

component may be an individual

object or a collection of

objects

DecoratorIntent: Modify the behavior of

individual objects without creating a new derived class

FaçadeIntent: Reduce the complexity

of elaborate subsystems by

providing a simplified

interface to them

FlyweightIntent: Reduce the number of

similar classes by sharing their commonality and passing

their differences as parameters

ProxyIntent:

Represent a complex object with a simpler one, thereby

postponing the instantiation of

the complex object until it is

truly needed

Page 2: Structural Patterns

Structural Pattern: AdapterWhen the client expects to interact with a class in a particular manner, it is sometimes necessary to “adapt” the interface of the class to accommodate those expectations.

Chapter 4 – Page 2

The client will call the adapter’s interface which, in turn, translates those calls into calls to the original interface of the class being adapted.This permits classes to work together in spite of incompatible interfaces.

Page 3: Structural Patterns

The Adapter PatternThe Client has been set up to collaborate with objects that conform to the domain-specific Target interface.

Chapter 4 – Page 3

The existing Adaptee interface is adapted to the Target interface by means of the Adapter.This solution is frequently needed when an old software component offers useful functionality, but its interface is incompatible with the architecture of a new system that is being developed.

Client Target

request()

Adapter

request()

Adaptee

specificRequest()

adaptee.SpecificRequest()

Page 4: Structural Patterns

Non-Software ExampleThe RoundHole client has been set up to check whether a RoundPeg target fits by checking its radius.

Chapter 4 – Page 4

The SquarePeg adaptee has a radius, not a width, but can be adapted to determine its “radius” by dividing its width by the square root of two.

RoundHolepeg

pegFits() : boolean

RoundPegradius

GetRadius()

SquarePegAdapter

GetRadius()

SquarePegwidth

GetWidth()

GetRadius() return squarePeg.GetWidth()/sqrt(2)

Note that the adaptee isn’t necessarily converted into an object of the target class, but it is adapted so the client’s needed functionality is available.

Page 5: Structural Patterns

Primitive Software ExampleThe client uses the (x,y) position of a Rectangle’s upper left corner and the Rectangle’s width and height to draw the Rectangle.

Chapter 4 – Page 5

The old LegacyRectangle uses the (x,y) positions of its upper left and lower right corners to draw it.The RectangleAdapter adapts the old-style drawing to the new style by converting the client’s information about the one corner, the width, and the height into the LegacyRectangle’s information about the two corners.

Rectangle

draw()

Client

LegacyRectanglelowXlowYhighXhighY

oldDraw()

RectangleAdapter

draw()

draw() return legacyRectangle.oldDraw()

Assumes that drawing is performed by specifying the rectangle's upper left coordinates, width, and height

Page 6: Structural Patterns

C++ Code for Rectangle AdapterChapter 4 – Page 6

#include <iostream>using namespace std;

typedef int Coordinate;typedef int Dimension;

// Target Interface: Abstract Superclassclass Rectangle { public: virtual void draw() = 0;};

// Adaptee: Old-style rectangleclass LegacyRectangle{ public: LegacyRectangle(Coordinate x1, Coordinate y1, Coordinate x2, Coordinate y2) { lowX = x1; lowY = y1; highX = x2; highY = y2; cout << "LegacyRectangle: create. (" << lowX << "," << lowY << ") => (" << highX << "," << highY << ")" << endl; } void oldDraw() { cout << "LegacyRectangle: oldDraw. (" << lowX << "," << lowY << ") => (" << highX << "," << highY << ")" << endl; }

Page 7: Structural Patterns

Chapter 4 – Page 7

private: Coordinate lowX; Coordinate lowY; Coordinate highX; Coordinate highY;};

// Adapter: Rectangle is the abstract class providing the interface, while// LegacyRectangle is the concrete class providing the implementation.class RectangleAdapter: public Rectangle, private LegacyRectangle{ public: RectangleAdapter(Coordinate x, Coordinate y, Dimension w, Dimension h): LegacyRectangle(x, y, x + w, y + h) { cout << "RectangleAdapter: create. (" << x << "," << y << "), width = " << w << ", height = " << h << endl; } virtual void draw() { cout << "RectangleAdapter: draw." << endl; oldDraw(); }};

void main() { Rectangle *r = new RectangleAdapter(120, 200, 60, 40); r->draw();}

Page 8: Structural Patterns

Chapter 4 – Page 8Adapter Example:External PolymorphismPolymorphism may be implemented even if the classes are not derived from the same base class.The ExecuteAdapter adapts the three old-style classes (Moe, Larry, and Curly) to the new target style (ExecuteInterface) by converting mapping each of their respective methods (doThis, doThat, and doTheOther) to the target’s execute method.

ExecuteInterface

execute()

Client

Moe

doThis()

method() return Moe::doThis() OR return Larry::doThat() OR return Curly::doTheOther()

Larry

doThat()

ExecuteAdapter

method() Curly

doTheOther()

Page 9: Structural Patterns

Chapter 4 – Page 9External Polymorphism C++ Code

#include <iostream>using namespace std;

// Target: Specifies the new interfaceclass ExecuteInterface { public: virtual ~ExecuteInterface() {} virtual void execute() = 0; };

// Adapter: "Maps" the new interface to the legacy implementationtemplate <class TYPE>class ExecuteAdapter: public ExecuteInterface { public: ExecuteAdapter(TYPE *o, void(TYPE:: *m)()) { object = o; method = m; } ~ExecuteAdapter() { delete object; } void execute() { (object->*method)(); } private: TYPE *object; // ptr-to-object attribute void(TYPE:: *method)(); // ptr-to-member function attribute};

Page 10: Structural Patterns

Chapter 4 – Page 10// Adaptees: Three totally incompatible classes with

// no common base class and no hope of polymorphismclass Moe { public: ~Moe() { cout << "Moe::destructor" << endl; } void doThis() { cout << "Moe::doThis()" << endl; }};

class Larry{ public: ~Larry() { cout << "Larry::destructor" << endl; } void doThat() { cout << "Larry::doThat()" << endl; }};

class Curly{ public: ~Curly() { cout << "Curly::destructor" << endl; } void doTheOther() { cout << "Curly::doTheOther()" << endl; }};

Page 11: Structural Patterns

Chapter 4 – Page 11

// An array of new interfaces is returned, adapted from the old implementationsExecuteInterface** initialize() { ExecuteInterface** array = new ExecuteInterface*[3]; array[0] = new ExecuteAdapter<Moe> (new Moe(), &Moe::doThis); array[1] = new ExecuteAdapter<Larry> (new Larry(), &Larry::doThat); array[2] = new ExecuteAdapter<Curly> (new Curly(), &Curly::doTheOther); return array;}

// The client uses the new interface, effectively producing an "external" polymorphismvoid main(){ int i; ExecuteInterface** objects = initialize(); for (i = 0; i < 3; i++) objects[i]->execute(); for (i = 0; i < 3; i++) delete objects[i]; delete objects;}

Page 12: Structural Patterns

Adapter Pattern AdvantagesChapter 4 – Page 12• The Adapter Design tends to make things work after they’ve

already been designed, compelling normally incompatible designs to collaborate successfully.

• By adapting new interfaces to old implementations, the old code becomes reusable.

• In addition, the client is freed from the burden of having to account for object differences, since it treats all objects the same way. In addition, new types of objects can be accommodated without making changes to the client code.