Published by orzz.org(). (http://orzz.org/cpp_composite/)
组合模式是一个很有意思的模式。
它的特征在于自身和自身的组合 —— 我们可以先想象有这么一个对象,它是一个集合(可以是数组或链表或其他的容器),它内部的子对象和它是同一个类型的对象。
恩,想象到这里就够了,这就是一个组合模式的感觉。这样想的话,组合模式似乎有点像一棵多叉树,每个结点下面都可以任意组合多个子节点,类图似乎也应该像一棵树的感觉。
不过由于组合模式的重点在于自身和自身的组合,所以类图其实并不复杂:
蓝色的IFunction,表示一个我们需要的操作;
绿色的IComponent,是组合接口,它封装了为了支持“组合”这个功能而必须的一组方法:“Add”和“Remove”。当然,方法名称不是固定的,只要能够表达这两个语义即可。同时,它需要从IFunction继承,这样所有的组合对象都必须实现我们需要的操作。
组合对象可以有两种,一种是可以添加别的对象的CComposite;另一种则是只能被其他对象组合,而自身无法再继续添加新对象的CLeaf(其实就是只能当树叶的结点,有点像final?)。
严格来说,CLeaf可以算作是“阉割版”的CComposite,如果没有Operation(操作)上的区别,它完全可以从CComposite继承,然后把“Add”和“Remove”方法private(私有化)掉。
当然了,如果不需要“叶子”结点的话,在实际项目中完全可以不写这么一个东西。设计模式本身是非常灵活的,它里面的每一个对象都代表了一种逻辑上的封装或抽象。在实际使用的时候,不需要的抽象自然不需要去实现它,关键在于理解和运用这些抽象。
- 代码示例
这里的示例实现和上文中的类图有部分不一致的地方。比如说IComponent接口增加了一个Display方法,用来显示在当前深度下的IComponent。之所以增加这个方法,主要是为了在控制台下打印出组合模式组合完成后的树的形状。
下面给出完整的代码示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 |
////////////////////////////////////////////////////////////////// // 组合模式 C++示例 // // Author: 木头云 // Blog: http://darkc.at // E-Mail: memleak@darkc.at // Version: 1.0.824.1512(2009/08/24) ////////////////////////////////////////////////////////////////// #include "stdafx.h" ////////////////////////////////////////////////////////////////// // 功能接口类 class IFunction abstract { public: virtual ~IFunction() { } public: virtual void Operation() = 0; }; // 组合接口类 class IComponent abstract : public IFunction { protected: _tstring name; public: IComponent(const _tstring& name) { this->name = name; } virtual ~IComponent() { } public: virtual void Add(const TSmartPtr<IComponent>& c) = 0; virtual void Remove(const TSmartPtr<IComponent>& c) = 0; virtual void Display(unsigned int depth = 0) = 0; }; ////////////////////////////////////////////////////////////////// // 叶节点对象类(功能类) class CLeaf : public IComponent { public: CLeaf(const _tstring& name) : IComponent(name) { } private: // 叶节点不具备对外的Add与Remove接口 virtual void Add(const TSmartPtr<IComponent>& c) { _tcout << _T("不能向叶节点添加对象") << endl; } virtual void Remove(const TSmartPtr<IComponent>& c) { _tcout << _T("不能从叶节点删除对象") << endl; } public: virtual void Display(unsigned int depth) { _tstring str(depth * 4, _T('-')); _tcout << str + name << endl; } virtual void Operation() { _tcout << name << endl; } }; // 组合对象类 class CComposite : public IComponent { private: typedef list< TSmartPtr<IComponent> > cld_lst; private: cld_lst children; public: CComposite(const _tstring& name) : IComponent(name) { } public: virtual void Add(const TSmartPtr<IComponent>& c) { cld_lst::iterator ite = find(children.begin(), children.end(), c); if( ite == children.end() ) children.push_back(c); } virtual void Remove(const TSmartPtr<IComponent>& c) { children.remove(c); } virtual void Display(unsigned int depth) { _tstring str(depth * 4, _T('-')); _tcout << str + name << endl; // 遍历集合显示下级对象 cld_lst::iterator ite; for( ite = children.begin(); ite != children.end(); ++ite ) { (*ite)->Display(depth + 1); } } virtual void Operation() { cld_lst::iterator ite; for( ite = children.begin(); ite != children.end(); ++ite ) { (*ite)->Operation(); } } }; ////////////////////////////////////////////////////////////////// // 主函数 int _tmain(int argc, _TCHAR* argv[]) { // 生成树根,根上长出叶A和B TSmartPtr<IComponent> root = new CComposite(_T("root")); root->Add(new CLeaf(_T("leaf A"))); root->Add(new CLeaf(_T("leaf B"))); // 树根长出分支X,根上长出叶XA和XB TSmartPtr<IComponent> comp = new CComposite(_T("comp X")); comp->Add(new CLeaf(_T("leaf XA"))); comp->Add(new CLeaf(_T("leaf XB"))); root->Add(comp); // 分支X长出分支X2,根上长出叶X2A和X2B TSmartPtr<IComponent> comp2 = new CComposite(_T("comp X2")); comp2->Add(new CLeaf(_T("leaf X2A"))); comp2->Add(new CLeaf(_T("leaf X2B"))); comp->Add(comp2); // 根部长出叶C和D root->Add(new CLeaf(_T("leaf C"))); TSmartPtr<CLeaf> leaf = new CLeaf(_T("leaf D")); root->Add(leaf); // 叶子D被吹走了 root->Remove(leaf); // 显示大树的样子 _tcout << _T("显示树结构:") << endl; root->Display(); _tcout << endl; // 调用每个叶子的方法 _tcout << _T("调用叶子功能:") << endl; root->Operation(); _tcout << endl; return 0; } ////////////////////////////////////////////////////////////////// /* Composite模式将对象组合成树形结构以表示"部分-整体"的层次结构. Composite模式使得用户对单个对象和组合对象的使用具有一致性. 可以在组合接口类之上定义好功能接口,这样组合模式中的每个对象都将具有相同的功能接口. 组合模式中真正实施功能的对象是叶子节点,每个上层节点对象负责将其下面的节点对象(可能是叶子,也可能不是) 串连成一个集合对象,通过遍历这个集合来访问叶子(功能)节点的功能接口. */ ////////////////////////////////////////////////////////////////// |
代码运行结果如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
显示树结构: root ----leaf A ----leaf B ----comp X --------leaf XA --------leaf XB --------comp X2 ------------leaf X2A ------------leaf X2B ----leaf C 调用叶子功能: leaf A leaf B leaf XA leaf XB leaf X2A leaf X2B leaf C |
- 总结
组合模式可以把所有具有类似功能的对象组合成树状结构,在所有“部分和整体具有相似性”的情况下,都可以斟酌使用。
比如界面开发里,窗口-控件之间的关系(父子关系);资源管理器的树状目录列表等。
Published by orzz.org(). (http://orzz.org/cpp_composite/)