为方便读者,本文已添加至索引:
在Composite(组合)模式中,用户可以使用多个简单的组件以形成较大的组件,而这些组件还可能进一步组合成更大的。它重要的特性是能够让用户一致地对待单个对象和组合对象。不知大家是否还记得女巫格琳达(见笔记Facade模式),她的小屋经营得很顺利,给小伙伴们的生活带来了极大地便利。今天,她又推出了一项全新的销售项目,那就是“私人订制自主行动型魔法小人偶-I”。乍看之下是个稻草人模样,但其实客人们能够通过自己订制小人偶的不同部件,组装成一个可以按照预先设定的期望目标而自主行动的魔法人偶。他们可以帮忙播种,耕地,烹饪,甚至战斗等等等等。
女巫格琳达在设计这个小人偶原型时,采用了Composite模式从而简化了客户们的操作,同时也能利用清晰的树形结构来展示订制的全部内容。在我们进入到示例部分讲解小人偶相关代码之前,先来具体了解下Composite模式的基本知识:
从上文的UML图中,可以看到Composite模式描述了如何使用递归组合,使得用户不必对单个类与组合类进行区别。而实现这一点的关键,在于Component抽象类,它既能代表单个组件,又能代表容器。
对于我们的魔法小人偶-I型而言,我们同样定义一个Component类为接下来所有的部件定义一个接口。
1 class Component { 2 public: 3 virtual ~Component(); 4 5 const char* name() { return _name; } 6 7 virtual int myFunction(); // power on the function of the component. 8 virtual int myValue(); // count the value of the component. 9 10 virtual void add(Component*); 11 virtual void remove(Component*); 12 virtual Iterator<Component*>* createIterator(); 13 14 protected: 15 Component(const char*); 16 17 private: 18 const char* _name; 19 };
我们看到Component声明了一些操作来返回一个部件的属性,譬如说它的价格等。子类将为指定的部件实现这些接口。而对于createIterator操作,它能够返回一个访问它零件的Iterator,从而能够在管理零件的时候,进行遍历。
Component类的子类有很多,我们将不会全部讲述(那会显得很冗余)。我们首先看到的是Leaf型的组件,它们不是容器,比如装在原型里面的驱动装置,穿在外面的衣服,戴在头上的帽子,可以使用的武器、工具等等。比如我们Clothes类:
1 class Clothes : public Component { 2 public: 3 Clothes(const char*); 4 virtual ~Clothes(); 5 6 virtual int myFunction(); 7 virtual int myValue(); 8 };
另一些是Composite型的组件,它们作为容器能够包含其他部件。这种组件的基类CompositeComponent:
1 class CompositeComponent : public Component { 2 virtual ~CompositeComponent(); 3 4 virtual int myFunction(); 5 virtual int myValue(); 6 7 virtual void add(Component*); 8 virtual void remove(Component*); 9 virtual Iterator<Component*>* createIterator(); 10 11 protected: 12 CompositeComponent(const char*); 13 14 private: 15 List<Component*> _component; 16 };
它为访问和管理子部件定义了一些操作。操作add/remove将从存储在_component成员变量中的部件列表中插入/删除部件。而作为容器的myValue操作,通过使用createIterator,来累加子部件的价格。
1 int CompositeComponent::myValue() { 2 Iterator<Component*>* iter = createIterator(); 3 int total = 0; 4 for (iter->first(); !iter->isDone(); iter->next()) { 5 total += iter->current()->myValue(); 6 } 7 delete iter; 8 return total; 9 }
CompositeComponent类的子类之一ProtoBody,是最基本的人偶外壳容器,格琳达可以通过在里面安置一些驱动器Drive,传感器Sensor等来使得它得以正常运作。
1 class ProtoBody : public CompositeComponent { 2 public: 3 ProtoBody(const char*); 4 virtual ~ProtoBody(); 5 6 virtual int myFunction(); 7 virtual int myValue(); 8 };
好啦,我们还可以定义一些相似的其他容器,譬如战斗人偶的武器袋WeaponBag等等。我们可以简单地来模拟订制一个能够保卫领土的战斗机器人:
1 ProtoBody* body = new ProtoBody("A strong and tough body"); 2 3 WeaponBag* bag = new WeaponBag("Weapon bag"); 4 bag->add(new Weapon("Sharpen Sword")); 5 bag->add(new Shield("Hard Shield")); 6 7 body->add(bag); 8 body->add(new Drive("Fight For Honor!")); 9 body->add(new Clothes("Cool Armor")); 10 11 cout << "The total price is " << body->myValue() << endl;
对于我们的设计可以看下面这张图:
从上面我们可以看到,Composite模式有如下一些特点:
同时,我们在实现的时候需要注意以下几点:
今天的笔记就到这里了,欢迎大家批评指正!如果觉得可以的话,好文推荐一下,我会非常感谢的!
[学习笔记]设计模式之Composite,布布扣,bubuko.com
原文:http://www.cnblogs.com/xieziyu/p/3614283.html