// Purpose. Composite // Strategy. Use recursive composition // to create a heterogeneous aggregate #include // that can be treated homogeneously. enum NodeType { FileT, DirT }; // int g_indent = 0; // Benefit. No more type checking and // type casting (coupling between Dir class File { // and File is gone, Dir is only public: // coupled to abstract base class) File( char* n ) { type_ = FileT; strcpy( name_, n ); } class AbsFile { NodeType getType() { return type_; } public: void ls() { virtual void ls() = 0; for (int i=0; i < g_indent; i++) protected: cout << ' '; char name_[20]; cout << name_ << endl; } static int indent_; private: }; NodeType type_; int AbsFile::indent_ = 0; char name_[20]; }; class File: public AbsFile { public: class Dir { File( char* n ) { public: strcpy( name_, n ); } Dir( char* n ) { type_ = DirT; void ls() { strcpy( name_, n ); total_ = 0; } for (int i=0; i < indent_; i++) NodeType getType() { return type_; } cout << ' '; void add( File* f ) { cout << name_ << endl; } files_[total_++] = f; }; } void ls() { class Dir : public AbsFile { for (int i=0; i < g_indent; i++) public: cout << ' '; Dir( char* n ) { cout << name_ << ":" << endl; strcpy( name_, n ); total_ = 0; } g_indent += 3; void add( AbsFile* f ) { for (int i=0; i < total_; i++) files_[total_++] = f; } if (files_[i]->getType() void ls() { == DirT) for (int i=0; i < indent_; i++) ((Dir*) files_[i])->ls(); cout << ' '; else cout << name_ << ":" << endl; files_[i]->ls(); indent_ += 3; g_indent -= 3; } for (int i=0; i < total_; i++) private: files_[i]->ls(); NodeType type_; indent_ -= 3; } char name_[20]; private: File* files_[10]; AbsFile* files_[10]; int total_; int total_; }; }; void main( void ) void main( void ) { { Dir one("1"), two("2"), thr("3"); Dir one("1"), two("2"), thr("3"); File a("a"), b("b"), c("c"), File a("a"), b("b"), c("c"), d("d"), e("e"); d("d"), e("e"); one.add( &a ); one.add( &a ); one.add( (File*) &two ); one.add( &two ); one.add( &b ); one.add( &b ); two.add( &c ); two.add( &c ); two.add( &d ); two.add( &d ); two.add( (File*) &thr ); two.add( &thr ); thr.add( &e ); thr.add( &e ); one.ls(); one.ls(); } } // 1: // d // 1: // d // a // 3: // a // 3: // 2: // e // 2: // e // c // b // c // b // Purpose. Composite design pattern // // 1. Identify the scalar/primitive classes and vector/container classes // 2. Create an "interface" (lowest common denominator) that can make all // concrete classes "interchangeable" // 3. All concrete classes declare an "is a" relationship to the interface // 4. All "container" classes couple themselves to the interface (recursive // composition, Composite "has a" set of children up the "is a" hierarchy) // 5. "Container" classes use polymorphism as they delegate to their children #include #include using namespace std; // 2. Create an "interface" (lowest common denominator) class Component { public: virtual void traverse() = 0; }; class Leaf : public Component { // 1. Scalar class 3. "isa" relationship int value; public: Leaf( int val ) { value = val; } void traverse() { cout << value << ' '; } }; class Composite : public Component { // 1. Vector class 3. "isa" relationship vector children; // 4. "container" coupled to the interface public: // 4. "container" class coupled to the interface void add( Component* ele ) { children.push_back( ele ); } void traverse() { for (int i=0; i < children.size(); i++) // 5. Use polymorphism to delegate to children children[i]->traverse(); } }; void main( void ) { Composite containers[4]; for (int i=0; i < 4; i++) for (int j=0; j < 3; j++) containers[i].add( new Leaf( i * 3 + j ) ); for (i=1; i < 4; i++) containers[0].add( &(containers[i]) ); for (i=0; i < 4; i++) { containers[i].traverse(); cout << endl; } } // 0 1 2 3 4 5 6 7 8 9 10 11 // 3 4 5 // 6 7 8 // 9 10 11 // Purpose. Composite design pattern - multiple container classes #include #include using namespace std; class Component { public: virtual void traverse() = 0; }; class Primitive : public Component { int value; public: Primitive( int val ) { value = val; } void traverse() { cout << value << " "; } }; class Composite : public Component { vector children; int value; public: Composite( int val ) { value = val; } void add( Component* c ) { children.push_back( c ); } void traverse() { cout << value << " "; for (int i=0; i < children.size(); i++) children[i]->traverse(); } }; class Row : public Composite { public: // Two different kinds of "con- Row( int val ) : Composite( val ) { } // tainer" classes. Most of the void traverse() { // "meat" is in the Composite cout << "Row"; // base class. Composite::traverse(); } }; class Column : public Composite { public: Column( int val ) : Composite( val ) { } void traverse() { cout << "Col"; Composite::traverse(); } }; void main( void ) { Row first( 1 ); // Row1 Column second( 2 ); // | Column third( 3 ); // +-- Col2 Row fourth( 4 ); // | | Row fifth( 5 ); // | +-- 7 first.add( &second ); // +-- Col3 first.add( &third ); // | | third.add( &fourth ); // | +-- Row4 third.add( &fifth ); // | | | first.add( &Primitive( 6 ) ); // | | +-- 9 second.add( &Primitive( 7 ) ); // | +-- Row5 third.add( &Primitive( 8 ) ); // | | | fourth.add( &Primitive( 9 ) ); // | | +-- 10 fifth.add( &Primitive(10 ) ); // | +-- 8 first.traverse(); cout << '\n'; // +-- 6 } // Row1 Col2 7 Col3 Row4 9 Row5 10 8 6 // Purpose. Composite and Prototype - lightweight persistence #pragma warning( disable : 4786 ) #include #include #include #include #include using namespace std; class Component { public: virtual ~Component() { } virtual void traverse() = 0; virtual Component* clone() = 0; virtual void initialize( ifstream& ) = 0; }; namespace Factory { map hash; void add( string s, Component* c ) { hash[s] = c; } Component* makeComponent( string name ) { return hash[name]->clone(); } } class Leaf : public Component { string value; public: ~Leaf() { cout << 'd' << value << ' '; } /*virtual*/ void traverse() { cout << value << ' '; } /*virtual*/ Component* clone() { return new Leaf(); } /*virtual*/ void initialize( ifstream& is ) { is >> value; } }; class Composite : public Component { vector children; string value; public: ~Composite() { cout << 'd' << value << ' '; for (int i=0; i < children.size(); i++) delete children[i]; } void add( Component* c ) { children.push_back( c ); } /*virtual*/ void traverse() { cout << value << ' '; for (int i=0; i < children.size(); i++) children[i]->traverse(); } /*virtual*/ Component* clone() { return new Composite(); } /*virtual*/ void initialize( ifstream& is ) { is >> value; string str, delim( "/"+value ); is >> str; while (str != delim) { add( Factory::makeComponent( str ) ); children[children.size()-1]->initialize( is ); is >> str; } } }; void main( void ) { Factory::add( "comp", new Composite() ); Factory::add( "leaf", new Leaf() ); ifstream is( "compositeCreate.txt" ); string str; is >> str; Component* root = Factory::makeComponent( str ); root->initialize( is ); root->traverse(); cout << '\n'; delete root; cout << '\n'; } /*** comp a leaf 1 comp b comp d leaf 8 leaf 9 /d leaf 4 comp e leaf 10 leaf 11 leaf 12 /e leaf 2 comp c leaf 5 leaf 6 leaf 7 /c /b leaf 3 /a ***/ // a 1 b d 8 9 4 e 10 11 12 2 c 5 6 7 3 // da d1 db dd d8 d9 d4 de d10 d11 d12 d2 dc d5 d6 d7 d3