2009-08-20

Composite pattern

[category]
Structural pattern

[brief description]
This pattern "compose" objects into tree structures to represent part-whole hierarchies.

[detail description]
This pattern provides a tree structures data model. Think about directories and files, directories are composite and files are leafs. Directories can have files in themselves as their children.

[expression in UML]

┌─────────┐
│ Component │
├─────────┤
├─────────┤0..*
│ + operation() │────────―─┐
│ + add() │child │
│ + remove() │ │
│ + getChild() │ │
└─────────┘ │
△ │
│ │
┌──────┴───────┐ │
│ │ │
┌────┴───┐ ┌────┴────┐ │
│ Leaf │ │ Composite │ │
├────────┤ ├─────────┤ │
├────────┤ ├─────────┤ │
│ + operation() │ │ + operation() │ 1 │
└────────┘ │ + add() │◇─┘
│ + remove() │ parent
│ + getChild() │
└─────────┘

[sample code]

(C++)

#include <stdexcept>
#include <iostream>
#include <vector>
#include <string>

enum Type
{
dic,
file
};

class Component
{
public:
Component() {}
Component(Type t_, const char* name_)
: t(t_), name(name_)
{}
virtual ~Component() {}
virtual void operation() {}
Type getType() { return t; }
const char* getName() { return name; }
virtual void add(Component* c) { throw std::runtime_error("This method is not implemented."); }
virtual void remove() { throw std::runtime_error("This method is not implemented."); }
virtual std::vector getChild()
{ throw std::runtime_error("This method is not implemented."); }
virtual int getSize() { throw std::runtime_error("This method is not implemented."); }

private:
Type t;
const char* name;
};

class Directory
: public Component
{
public:
Directory(const char* name)
: Component(dic, name)
{}
virtual ~Directory()
{
for (int i = 0; i < children.size(); i++) {
delete children[i];
}
}
virtual void operation()
{
std::cout << getName() << std::endl;
}
virtual void add(Component* c)
{
children.push_back(c);
}
virtual void remove()
{
Component* c = *(children.end() - 1);
delete c;
children.pop_back();
}
virtual std::vector getChild() { return children; }
virtual int getSize() { return children.size(); }

private:
std::vector children;
int size;
};

class File
: public Component
{
public:
File(const char* name)
: Component(file, name)
{}
virtual ~File() {}

virtual void operation() { std::cout << getName() << std::endl; }
};

void printTree(Component* com, const std::string indent)
{
std::cout << indent;
if (file == com->getType()) {
com->operation();
} else if (dic == com->getType()) {
com->operation();
int size = com->getSize();
std::vector children = com->getChild();
for (int i = 0; i < size; i++) {
Component* c = children[i];
printTree(c, indent + " ");
}
}
}

int main(int, char**)
{
Component* d1 = new Directory("dic 1");
Component* f1 = new File("file 1");

d1->add(f1);

Component* d2 = new Directory("dic 2");
d1->add(d2);

Component* f2 = new File("file 2");
d2->add(f2);

printTree(d1, "");

return 0;
}

No comments:

Post a Comment