// Purpose. Decorator design pattern // 1. Create a "lowest common denominator" that makes classes interchangeable // 2. Create a second level base class for optional functionality // 3. "Core" class and "Decorator" class declare an "isa" relationship // 4. Decorator class "hasa" instance of the "lowest common denominator" // 5. Decorator class delegates to the "hasa" object // 6. Create a Decorator derived class for each optional embellishment // 7. Decorator derived classes delegate to base class AND add extra stuf // 8. Client has the responsibility to compose desired configurations #include using namespace std; class Widget { public: virtual void draw() = 0; }; // 1. "lowest common denom" class TextField : public Widget { // 3. "Core" class & "isa" int width, height; public: TextField( int w, int h ) { width = w; height = h; } /*virtual*/ void draw() { cout << "TextField: " << width << ", " << height << '\n'; } }; // 2. 2nd level base class class Decorator : public Widget { // 3. "isa" relationship Widget* wid; // 4. "hasa" relationship public: Decorator( Widget* w ) { wid = w; } /*virtual*/ void draw() { wid->draw(); } // 5. Delegation }; class BorderDecorator : public Decorator { public: // 6. Optional embellishment BorderDecorator( Widget* w ) : Decorator( w ) { } /*virtual*/ void draw() { Decorator::draw(); // 7. Delegate to base class cout << " BorderDecorator" << '\n'; // and add extra stuff } }; class ScrollDecorator : public Decorator { public: // 6. Optional embellishment ScrollDecorator( Widget* w ) : Decorator( w ) { } /*virtual*/ void draw() { Decorator::draw(); // 7. Delegate to base class cout << " ScrollDecorator" << '\n'; // and add extra stuff } }; void main( void ) { // 8. Client has the responsibility to compose desired configurations Widget* aWidget = new BorderDecorator( new BorderDecorator( new ScrollDecorator( new TextField( 80, 24 )))); aWidget->draw(); } // TextField: 80, 24 // ScrollDecorator // BorderDecorator // BorderDecorator // Purpose. Inheritance run amok #include using namespace std; class A { public: virtual void doIt() { cout << 'A'; } }; class AwithX : public A { void doX() { cout << 'X'; } public: /*virtual*/ void doIt() { A::doIt(); doX(); } }; class AwithY : public A { protected: void doY() { cout << 'Y'; } public: /*virtual*/ void doIt() { A::doIt(); doY(); } }; class AwithZ : public A { protected: void doZ() { cout << 'Z'; } public: /*virtual*/ void doIt() { A::doIt(); doZ(); } }; class AwithXY : public AwithX, public AwithY { public: /*virtual*/ void doIt() { AwithX::doIt(); AwithY::doY(); } }; class AwithXYZ : public AwithX, public AwithY, public AwithZ { public: /*virtual*/ void doIt() { AwithX::doIt(); AwithY::doY(); AwithZ::doZ(); } }; void main( void ) { AwithX anX; AwithXY anXY; AwithXYZ anXYZ; anX.doIt(); cout << '\n'; anXY.doIt(); cout << '\n'; anXYZ.doIt(); cout << '\n'; } // AX // AXY // AXYZ // Purpose. Replacing inheritance with wrapping-delegation // // Discussion. Use aggregation instead of inheritance to implement // embellishments to a "core" object. Client can dynamically compose // permutations, instead of the architect statically wielding multiple // inheritance. #include using namespace std; class I { public: virtual ~I() { } virtual void doIt() = 0; }; class A : public I { public: ~A() { cout << "A dtor" << '\n'; } /*virtual*/ void doIt() { cout << 'A'; } }; class D : public I { I* wrappee; public: D( I* inner ) { wrappee = inner; } ~D() { delete wrappee; } /*virtual*/ void doIt() { wrappee->doIt(); } }; class X : public D { public: X( I* core ) : D(core) { } ~X() { cout << "X dtor" << " "; } /*virtual*/ void doIt() { D::doIt(); cout << 'X'; } }; class Y : public D { public: Y( I* core ) : D(core) { } ~Y() { cout << "Y dtor" << " "; } /*virtual*/ void doIt() { D::doIt(); cout << 'Y'; } }; class Z : public D { public: Z( I* core ) : D(core) { } ~Z() { cout << "Z dtor" << " "; } /*virtual*/ void doIt() { D::doIt(); cout << 'Z'; } }; void main( void ) { I* anX = new X( new A ); I* anXY = new Y( new X( new A ) ); I* anXYZ = new Z( new Y( new X( new A ) ) ); anX->doIt(); cout << '\n'; anXY->doIt(); cout << '\n'; anXYZ->doIt(); cout << '\n'; delete anX; delete anXY; delete anXYZ; } // AX // AXY // AXYZ // X dtor A dtor // Y dtor X dtor A dtor // Z dtor Y dtor X dtor A dtor // Purpose. Decorator - encoding and decoding layers of header/packet/trailer #include #include using namespace std; class Interface { public: virtual ~Interface() { } virtual void write( string& ) = 0; virtual void read( string& ) = 0; }; class Core : public Interface { public: ~Core() { cout << "dtor-Core\n"; } /*virtual*/ void write( string& b ) { b += "MESSAGE|"; } /*virtual*/ void read( string& ); }; class Decorator : public Interface { Interface* inner; public: Decorator( Interface* c ) { inner = c; } ~Decorator() { delete inner; } /*virtual*/ void write( string& b ) { inner->write( b ); } /*virtual*/ void read( string& b ) { inner->read( b ); } }; class Wrapper : public Decorator { string forward, backward; public: Wrapper( Interface* c, string str ) : Decorator(c) { forward = str; string::reverse_iterator it; it = str.rbegin(); for ( ; it != str.rend(); ++it) backward += *it; } ~Wrapper() { cout << "dtor-" << forward << " "; } void write( string& ); void read( string& ); }; void main( void ) { Interface* object = new Wrapper( new Wrapper( new Wrapper( new Core(), "123" ), "abc" ), "987" ); string buf; object->write( buf ); cout << "main: " << buf << endl; object->read( buf ); delete object; } // main: 987]abc]123]MESSAGE|321]cba]789] // Wrapper: 987 // Wrapper: abc // Wrapper: 123 // Core: MESSAGE // Wrapper: 321 // Wrapper: cba // Wrapper: 789 // dtor-987 dtor-abc dtor-123 dtor-Core void Core::read(string& b) { int num = b.find_first_of( '|' ); cout << "Core: " << b.substr(0,num) << '\n'; b = b.substr(num+1); } void Wrapper::write( string& b ) { b += forward + "]"; Decorator::write( b ); b += backward + "]"; } void Wrapper::read( string& b ) { int num = b.find_first_of( ']' ); cout << "Wrapper: " << b.substr(0,num) << '\n'; b = b.substr(num+1); Decorator::read( b ); num = b.find_first_of( ']' ); cout << "Wrapper: " << b.substr(0,num) << '\n'; b = b.substr(num+1); }