组合模式( Composite ) - 结构型模式
组合模式是将对象之间的关系以数据结构中的 2 叉树表现出来,使得客户端将单纯的元素与复杂元素同等看待,这样的话使得用户在操作不同的子类元素时可以和根节点元素一样操作,在透明模式下即根元素和叶元素公用同一个接口达到共同的结果。组合模式就是解决部分与整体的关系的一种模式。
如在项目开发中遇到这样的一个需求,要求罗列出系统中所有职责岗位上的用户信息(职员名称和薪水)。这是一个很简单的需求,大多数程序员都能很轻易的写出来。跟我们今天讲的组合模式有联系吗?当然有啦。我们先来看看需求:
我们知道在一个公司里有很多岗位比如(总经理、副总经理、销售部经理、财务部经理,销售员,财务员。。。。)把公司里的所有职员按照所在岗位划分出来,我们先来归类,销售员归销售部经理管,财务员归财务部经理管,销售部经理、财务部经理归副总经理管,副总经理归总经理管。这样我们不难想想出这样的结构图:
<shapetype id="_x0000_t75" coordsize="21600,21600" o:spt="75" o:preferrelative="t" path="m@4@5l@4@11@9@11@9@5xe" filled="f" stroked="f"><stroke joinstyle="miter"></stroke><formulas><f eqn="if lineDrawn pixelLineWidth 0"></f><f eqn="sum @0 1 0"></f><f eqn="sum 0 0 @1"></f><f eqn="prod @2 1 2"></f><f eqn="prod @3 21600 pixelWidth"></f><f eqn="prod @3 21600 pixelHeight"></f><f eqn="sum @0 0 1"></f><f eqn="prod @6 1 2"></f><f eqn="prod @7 21600 pixelWidth"></f><f eqn="sum @8 21600 0"></f><f eqn="prod @7 21600 pixelHeight"></f><f eqn="sum @10 21600 0"></f></formulas><path o:extrusionok="f" gradientshapeok="t" o:connecttype="rect"></path><lock v:ext="edit" aspectratio="t"></lock></shapetype><shape id="_x0000_i1025" style="WIDTH: 163.5pt; HEIGHT: 276pt" type="#_x0000_t75" o:ole=""><imagedata src="file:///C:%5CDOCUME~1%5CWensi%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image001.emz" o:title=""></imagedata></shape> (图 1 )
依据图 1 我们用面向对象的语言来描述他(这里我简单的画了一个关系图并不是把所有公司部门都罗列出来,只是列举了其中的一些列子)。
大家看了下面图可能有点奇怪,怎么那么多部门都没有了呢,只有一个 boss 和 employees 呢?
<shape id="_x0000_i1026" style="WIDTH: 414.75pt; HEIGHT: 378pt" type="#_x0000_t75"><imagedata src="file:///C:%5CDOCUME~1%5CWensi%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image003.png" o:title="EmployeeDiagram"></imagedata></shape>
首先:不管你是什么职位在哪个岗位在公司这个大背景下(容器)所有人都是公司的一个部分,所以我们抽象出一个职员的抽象类 Employee 。对于职员来说他们的上级主管都是他们的大 BOSS (老板)因为你是听从他的调配的所以在我们这里只把他们抽象出来一个 Boss 和 Employees 类 Employees 是页节点所以子集的因为职位上没有什么是底层职工的下级,而 Boss 不同 0 到多个下属 Employee (因为他的下属有可能也是一个小 Boss 或是 Employees )。
其次:每个部门都有负责人,对应每个岗位上的员工都有他们自己的 Boss
那么我们的目的就是把这些人一个个的划分到指定的部分中去。我们定义一个接口 IComposite 他专门为 boss 收集他的子职员。(注意:这里我只在 boss 类这里继承了这个接口规范而 Employees 并没有此接口,这里我用了安全的组合模式,还有一种是 Employees 也继承此接口这时这个模式是透明的组合模式用户对用户来说他们只需调用接口就可以不用估计是老板还是职员,但这也带来了负面影响因为 Employees 是没有下属的所有这里的接口通常是不用实现的,所以可能在调用是出现运行时错误所以是不安全的,而前者只有 Boss 才有此接口所有这种模式是类型安全的组合模式,到底需要用哪一个这需要在实际开发中仔细考虑的。)
让我们回头看看这个 OOD 设计是否合理,我们依据我们第二章的设计模式原则来判定
1. 是否符合开闭原则
我们在新增一种 Employee 类型是如果他不是页节点那么只需要实现 IComposite 接口用户就可以直接使用所有对内是不要修改原有代码,对外是可扩展的。
答案:符合
2. 是否符合里氏代换原则
Boss 和 Employees 都继承与 Employee
答案:符合
3. 是否符合抽象原则
答案:符合
4. 是否符合迪米特法则
答案:符合
总结 :组合模式
意图 :
将对象组合成树形结构以表示“整体 - 部分”的层次结构。 Composite 使得用户对单个对象和组合对象的使用具有一致性
动机 :
客户代码过多的依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(非抽象接口)的变化将引起客户代码的频繁变化代码的代码维护和扩展的困难,我们需要将客户代码与复杂的对象容器结构解偶。
适用性 :
l 想表示对象的部分 - 整体层次结构
l 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。
结构 :
<shape id="_x0000_i1027" style="WIDTH: 179.25pt; HEIGHT: 114pt" type="#_x0000_t75" alt=""><imagedata src="file:///C:%5CDOCUME~1%5CWensi%5CLOCALS~1%5CTemp%5Cmsohtml1%5C01%5Cclip_image005.gif" o:href="http://www.cnblogs.com/images/cnblogs_com/zhenyulu/Pic59.gif"><font face="Times New Roman" size="3"></font></imagedata></shape>
参与者 :
l 抽象构件( Component )角色 ( IComposite )
l 树叶构件( Leaf )角色 ( Employees )
l 树枝构件 (Boss)
Composite 模式的优点 :
1. 客户代码不依赖复杂对象本身的结构变化
2. 用户不需要特别关心复杂对象的具体结构只要等同于根对象操作
代码 :
http://download.csdn.net/source/360701