//
Purpose. Adapter
//
//
Discussion. The Adapter pattern
//
discusses how to "wrap" the old in-
// terface of a legacy
component, so
// that it can continue to contribute
// in a new
system. It is about "im- #include <iostream.h>
// pedance
matching" an old dog with
#include <stdio.h>
// new tricks (to mix metaphors). On
#include <time.h>
// the left, WimpyTime "hasa"
in-
// stance of the legacy component, class ManlyTime {
// and delegates the "heavy
lifting" public:
// to
it. On the right, private char* getTime() {
//
derivation is used to accomplish
static char buf[30];
// the same result. time_t
lt;
tm* ltStruct;
class ManlyTime { time( <
);
public: ltStruct =
localtime(<);
char*
getTime() {
strftime( buf, 30, "%H%M",
static char buf[30]; ltStruct );
time_t lt; return buf;
tm*
ltStruct;
}
time( <
); };
ltStruct = localtime(<);
strftime( buf, 30,
"%H%M", class WimpyTime
:
ltStruct ); private
ManlyTime {
return buf; public:
} char* getTime() {
};
static char buf[30];
char *ptr, mi[3], am[3];
class
WimpyTime {
int hr;
public: ptr =
ManlyTime::getTime();
char*
getTime() {
cout << "old interface time is "
static char buf[30]; << ptr <<
endl;
char *ptr, mi[3],
am[3]; strcpy( mi,
&(ptr[2]) );
int hr; ptr[2] = '\0';
ptr = imp_.getTime(); sscanf( ptr,
"%d", &hr );
cout
<< "old interface time is " strcpy( am, "AM" );
<< ptr << endl; if (hr > 12) {
strcpy( mi, &(ptr[2]) ); hr -= 12;
ptr[2] = '\0'; strcpy( am, "PM" ); }
sscanf( ptr, "%d", &hr
); sprintf( buf,
"%d:%s %s",
strcpy(
am, "AM" );
hr, mi, am );
if (hr
> 12) {
return buf;
hr -=
12; }
strcpy( am, "PM" ); } };
sprintf( buf, "%d:%s %s",
hr, mi, am ); void main( void )
return buf; {
}
WimpyTime newT;
private: char* ptr;
ManlyTime imp_; ptr =
newT.getTime();
}; cout << "new
interface time is "
<< ptr <<
endl;
void main( void ) }
{
WimpyTime newT; // old interface time is
1721
char* ptr; // new interface time is 5:21 PM
ptr = newT.getTime();
cout << "new interface time is
"
<< ptr <<
endl;
}
// old interface time is 1709
// new interface
time is 5:09 PM
// Purpose. Adapter design pattern demo
//
// Discussion. LegacyRectangle's interface is not
compatible with the
// system that would like to reuse it. An abstract base class is created
//
that specifies the desired interface.
An "adapter" class is defined
// that publicly inherits
the interface of the abstract class, and
// privately inherits the
implementation of the legacy component.
This
// adapter class "maps" or "impedance
matches" the new interface to the
// old implementation.
#include
<iostream.h>
typedef int Coordinate;
typedef int
Dimension;
/////////////////////////// Desired interface
///////////////////////////
class Rectangle {
public:
virtual void draw() = 0;
};
///////////////////////////
Legacy component ///////////////////////////
class LegacyRectangle {
public:
LegacyRectangle( Coordinate x1, Coordinate
y1,
Coordinate x2,
Coordinate y2 ) {
x1_ =
x1; y1_ = y1; x2_ = x2; y2_ = y2;
cout <<
"LegacyRectangle: create. (" << x1_ << ","
<< y1_
<<
") => (" << x2_ << "," << y2_ <<
")" << endl; }
void oldDraw() {
cout
<< "LegacyRectangle:
oldDraw. (" << x1_
<< "," << y1_
<< ") => (" << x2_ <<
"," << y2_ << ")" << endl; }
private:
Coordinate x1_;
Coordinate y1_;
Coordinate x2_;
Coordinate y2_;
};
///////////////////////////
Adapter wrapper ///////////////////////////
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();
}
//
LegacyRectangle: create. (120,200) => (180,240)
//
RectangleAdapter: create. (120,200),
width = 60, height = 40
// RectangleAdapter: draw.
//
LegacyRectangle: oldDraw. (120,200) => (180,240)
//
Purpose. Adapter design pattern
(External Polymorphism demo)
// 1. Specify the new desired
interface
// 2. Design a "wrapper" class that can
"impedance match" the old to the new
// 3. The client uses (is
coupled to) the new interface
// 4. The adapter/wrapper "maps"
to the legacy implementation
#include <iostream.h>
class
ExecuteInterface { public:
// 1. Specify the new i/f
virtual ~ExecuteInterface() { }
virtual void execute() = 0;
};
template <class
TYPE> //
2. Design a "wrapper" or
class ExecuteAdapter : public
ExecuteInterface { // "adapter" class
public:
ExecuteAdapter( TYPE* o, void (TYPE::*m)()
) { object = o; method =m; }
~ExecuteAdapter() { delete object; }
// 4. The adapter/wrapper "maps"
the new to the legacy implementation
void execute() /* the
new */ { (object->*method)();
}
private:
TYPE* object; //
ptr-to-object attribute
void
(TYPE::*method)(); /* the old */ // ptr-to-member-function
};
// attribute
// The
old: three totally incompatible classes
// no common base class,
class Fea { public: // no hope of
polymorphism
~Fea() { cout << "Fea::dtor"
<< endl; }
void doThis() {
cout << "Fea::doThis()" << endl; }
};
class
Feye { public:
~Feye() { cout << "Feye::dtor"
<< endl; }
void doThat() {
cout << "Feye::doThat()" << endl; }
};
class
Pheau { public:
~Pheau() { cout <<
"Pheau::dtor" << endl; }
void doTheOther() { cout <<
"Pheau::doTheOther()" << endl; }
};
/* the new
is returned */ ExecuteInterface** initialize() {
ExecuteInterface** array = new
ExecuteInterface*[3]; /* the old is below */
array[0] = new ExecuteAdapter<Fea>( new Fea(), &Fea::doThis
);
array[1] = new
ExecuteAdapter<Feye>( new
Feye(), &Feye::doThat );
array[2] = new ExecuteAdapter<Pheau>( new Pheau(), &Pheau::doTheOther );
return array;
}
void main(
void ) {
ExecuteInterface**
objects = initialize();
for (int i=0; i < 3; i++) objects[i]->execute(); // 3. Client uses the new
// (polymporphism)
for (i=0; i < 3; i++) delete
objects[i];
delete
objects;
}
// Fea::doThis()
// Feye::doThat()
//
Pheau::doTheOther()
// Fea::dtor
// Feye::dtor
//
Pheau::dtor