Composite

  • 要素の集合を表現するオブジェクトと、その集合に含まれる要素を表現するオブジェクトを、一様に扱えるようにしてツリー構造を実現する(再帰構造)
  • 階層の各層を別のクラスで表現すると、似たような機能を持つクラスが多数できてしまうのを解決できる
  • 新しいグループ単位を容易に追加できる
  • 乱用すると論理的に正しくない構造を作り出す恐れがある
  • 循環参照に注意

  1. #include <iostream>
  2. #include <string>
  3. #include <vector>
  4. #include <algorithm>
  5. using namespace std;
  6.  
  7. // Component
  8. class Graphic {
  9. public:
  10. virtual void print() = 0;
  11. };
  12.  
  13. // Composite
  14. class CompositeGraphic : public Graphic {
  15. public:
  16. // constructor
  17. CompositeGraphic(const string &name) {
  18. mName = name;
  19. }
  20. // print
  21. void print() {
  22. cout << mName << endl;
  23. vector<Graphic*>::iterator it;
  24. for (it = mChildGraphics.begin();
  25. it != mChildGraphics.end();
  26. ++it)
  27. {
  28. (*it)->print();
  29. }
  30. }
  31. // add
  32. void add(Graphic *graphic) {
  33. mChildGraphics.push_back(graphic);
  34. }
  35. void remove(Graphic *graphic) {
  36. vector<Graphic*>::iterator it;
  37. it = find(mChildGraphics.begin(), mChildGraphics.end(), graphic);
  38. if (it != mChildGraphics.end()) {
  39. delete *it;
  40. mChildGraphics.erase(it);
  41. }
  42. }
  43. private:
  44. vector<Graphic*> mChildGraphics;
  45. string mName;
  46. };
  47.  
  48. // Leaf
  49. class Ellipse : public Graphic {
  50. public:
  51. // constructor
  52. Ellipse(const string &name) {
  53. mName = name;
  54. }
  55. // print
  56. void print() {
  57. cout << mName << endl;
  58. }
  59. string mName;
  60. };
  61.  
  62. // Client
  63. int main() {
  64. // initialize four ellipses
  65. Ellipse *ellipse1 = new Ellipse("Ellipse 1");
  66. Ellipse *ellipse2 = new Ellipse("Ellipse 2");
  67. Ellipse *ellipse3 = new Ellipse("Ellipse 3");
  68. Ellipse *ellipse4 = new Ellipse("Ellipse 4");
  69.  
  70. // initialize three composite graphics
  71. CompositeGraphic *graphic = new CompositeGraphic("Graphic");
  72. CompositeGraphic *graphic1 = new CompositeGraphic("Graphic 1");
  73. CompositeGraphic *graphic2 = new CompositeGraphic("Graphic 2");
  74.  
  75. // Composes the graphics
  76. graphic1->add(ellipse1);
  77. graphic1->add(ellipse2);
  78. graphic1->add(ellipse3);
  79.  
  80. graphic2->add(ellipse4);
  81.  
  82. graphic->add(graphic1);
  83. graphic->add(graphic2);
  84.  
  85. // prints the complete graphic
  86. graphic->print();
  87.  
  88. return 0;
  89. }
  90.  

出力
Graphic
Graphic 1
Ellipse 1
Ellipse 2
Ellipse 3
Graphic 2
Ellipse 4


http://www.dofactory.com/Patterns/PatternComposite.aspx#_self1
を c++ にしたもの (Structural Example)
  1. #include <iostream>
  2. #include <string>
  3. #include <list>
  4. #include <algorithm>
  5. using namespace std;
  6.  
  7. // The 'Component' abstract class
  8. class Component {
  9. public:
  10. // constructor
  11. Component(const string &name) {
  12. _name = name;
  13. }
  14. virtual ~Component() {
  15. // delete 確認
  16. //cout << "delete " << _name << endl;
  17. }
  18. virtual void Add(Component *c) = 0;
  19. virtual void Remove(Component *c) = 0;
  20. virtual void Display(int depth) = 0;
  21. protected:
  22. string _name;
  23. };
  24.  
  25. // The 'Composite' class
  26. class Composite : public Component {
  27. public:
  28. // constructor
  29. Composite(const string &name) : Component(name) { }
  30. // destructor
  31. ~Composite() {
  32. list<Component*>::iterator it;
  33. for (it=_children.begin(); it!=_children.end(); ++it) {
  34. delete *it;
  35. }
  36. }
  37. // Add
  38. void Add(Component *component) {
  39. _children.push_back(component);
  40. }
  41. // Remove
  42. void Remove(Component *component) {
  43. list<Component*>::iterator it;
  44. if ((it = find(_children.begin(), _children.end(), component))
  45. != _children.end())
  46. {
  47. delete *it;
  48. _children.erase(it);
  49. }
  50. }
  51. // Display
  52. void Display(int depth) {
  53. string str(depth, '-');
  54. cout << str << _name << endl;
  55. // Recursively display child nodes
  56. list<Component*>::iterator it;
  57. for (it=_children.begin(); it!=_children.end(); ++it) {
  58. (*it)->Display(depth + 2);
  59. }
  60. }
  61. private:
  62. list<Component*> _children;
  63. };
  64.  
  65. // The 'Leaf' class
  66. class Leaf : public Component {
  67. public:
  68. // constructor
  69. Leaf(const string &name) : Component(name) { }
  70. // Add
  71. void Add(Component *c) {
  72. cout << "Cannot add to a leaf" << endl;
  73. }
  74. // Remove
  75. void Remove(Component *c) {
  76. cout << "Cannot remove from a leaf" << endl;
  77. }
  78. // Display
  79. void Display(int depth) {
  80. string str(depth, '-');
  81. cout << str << _name << endl;
  82. }
  83. };
  84.  
  85. // client
  86. int main() {
  87. // Create a tree structure
  88. Composite *root = new Composite("root");
  89. root->Add(new Leaf("Leaf A"));
  90. root->Add(new Leaf("Leaf B"));
  91.  
  92. Composite *comp = new Composite("Composite X");
  93. comp->Add(new Leaf("Leaf XA"));
  94. comp->Add(new Leaf("Leaf XB"));
  95.  
  96. root->Add(comp);
  97. root->Add(new Leaf("Leaf C"));
  98.  
  99. // Add and remove a leaf
  100. Leaf *leaf = new Leaf("Leaf D");
  101. root->Add(leaf);
  102. root->Remove(leaf);
  103.  
  104. // Recursively display tree
  105. root->Display(1);
  106.  
  107. delete root;
  108.  
  109. return 0;
  110. }
  111.  

出力
-root
---Leaf A
---Leaf B
---Composite X
-----Leaf XA
-----Leaf XB
---Leaf C


http://www.dofactory.com/Patterns/PatternComposite.aspx#_self2
を c++ にしたもの (Real World Example)
  1. #include <iostream>
  2. #include <string>
  3. #include <list>
  4. #include <algorithm>
  5. using namespace std;
  6.  
  7. // The 'Component' Treenode
  8. class DrawingElement
  9. {
  10. public:
  11. // constructor
  12. DrawingElement(const string &name) {
  13. _name = name;
  14. }
  15. // destructor
  16. virtual ~DrawingElement() {
  17. // delete 確認
  18. //cout << "deleting " << _name << endl;
  19. }
  20. virtual void Add(DrawingElement *d) = 0;
  21. virtual void Remove(DrawingElement *d) = 0;
  22. virtual void Display(int indent) = 0;
  23. protected:
  24. string _name;
  25. };
  26.  
  27. // The 'Leaf' class
  28. class PrimitiveElement : public DrawingElement {
  29. public:
  30. // constructor
  31. PrimitiveElement(const string &name) : DrawingElement(name) { }
  32. // Add
  33. void Add(DrawingElement *d) {
  34. cout << "Cannot add to a PrimitiveElement" << endl;
  35. }
  36. // Remove
  37. void Remove(DrawingElement *d) {
  38. cout << "Cannot remove to a PrimitiveElement" << endl;
  39. }
  40. // Display
  41. void Display(int indent) {
  42. string str(indent, '-');
  43. cout << str << " " << _name << endl;
  44. }
  45. };
  46.  
  47. // The 'Composite' class
  48. class CompositeElement : public DrawingElement {
  49. public:
  50. // constructor
  51. CompositeElement(const string &name) : DrawingElement(name) { }
  52. // destructor
  53. virtual ~CompositeElement() {
  54. list<DrawingElement*>::iterator it;
  55. for (it=elements.begin(); it!=elements.end(); ++it) {
  56. delete (*it);
  57. }
  58. }
  59. // Add
  60. void Add(DrawingElement *d) {
  61. elements.push_back(d);
  62. }
  63. void Remove(DrawingElement *d) {
  64. list<DrawingElement*>::iterator it;
  65. it = find(elements.begin(), elements.end(), d);
  66. if (it != elements.end()) {
  67. delete *it;
  68. elements.erase(it);
  69. }
  70. }
  71. void Display(int indent) {
  72. string str(indent, '-');
  73. cout << str << "+ " << _name << endl;
  74. list<DrawingElement*>::iterator it;
  75. for (it=elements.begin(); it!=elements.end(); ++it) {
  76. (*it)->Display(indent + 2);
  77. }
  78. }
  79. private:
  80. list<DrawingElement*> elements;
  81. };
  82.  
  83. // client
  84. int main() {
  85. // Create a tree structure
  86. CompositeElement *root = new CompositeElement("Picture");
  87. root->Add(new PrimitiveElement("Red Line"));
  88. root->Add(new PrimitiveElement("Blue Circle"));
  89. root->Add(new PrimitiveElement("Green Box"));
  90.  
  91. // Create a branch
  92. CompositeElement *comp = new CompositeElement("Two Circles");
  93. comp->Add(new PrimitiveElement("Black Circle"));
  94. comp->Add(new PrimitiveElement("White Circle"));
  95. root->Add(comp);
  96.  
  97. // Add and remove a PrimitiveElement
  98. PrimitiveElement *pe = new PrimitiveElement("Yellow Line");
  99. root->Add(pe);
  100. root->Remove(pe);
  101.  
  102. // Recursively display node
  103. root->Display(1);
  104.  
  105. delete root;
  106.  
  107. return 0;
  108. }
  109.  

出力
-+ Picture
--- Red Line
--- Blue Circle
--- Green Box
---+ Two Circles
----- Black Circle
----- White Circle



参考サイト

デザインパターンを“喩え話”で分かり易く理解する
http://www.netlaputa.ne.jp/~hijk/study/oo/designpattern.html



デザインパターンの骸骨たち
http://www002.upp.so-net.ne.jp/ys_oota/mdp/

デザインパターンの使い方: Composite
http://japan.internet.com/developer/20080905/26.html
最終更新:2012年02月29日 00:57