//
Purpose. Composite // Strategy. Use recursive composition
// to
create a heterogeneous aggregate
#include <string.h> // 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 <iostream>
#include
<vector>
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<Component*> 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 <iostream>
#include
<vector>
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<Component*> 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
<iostream>
#include <vector>
#include
<string>
#include <map>
#include <fstream>
using
namespace std;
class Component { public:
virtual ~Component() { }
virtual void traverse() = 0;
virtual Component* clone() = 0;
virtual void initialize(
ifstream& ) = 0;
};
namespace Factory {
map<string,Component*> 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<Component*> 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