// 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 // pedance matching" an old dog with #include // new tricks (to mix metaphors). On #include // 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 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 class ExecuteInterface { public: // 1. Specify the new i/f virtual ~ExecuteInterface() { } virtual void execute() = 0; }; template // 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( new Fea(), &Fea::doThis ); array[1] = new ExecuteAdapter( new Feye(), &Feye::doThat ); array[2] = new ExecuteAdapter( 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