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
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
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.
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()
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.
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
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; }
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();}
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()
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};
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; }};
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;}
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.