From Now On,Let us begin Design Patterns。
组合模式
定义
- 将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 Compose objects into tree structures to represent part-whole hierarchies. Composite lets clients treat individual objects and compositions of objects uniformly.
通用类图:
从定义中可以得到使用组合模式的环境为:在设计中想表示对象的“部分-整体”层次结构;希望用户忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象。
角色说明:
抽象构件角色Component:它为组合中的对象声明接口,也可以为共有接口实现缺省行为。
树叶构件角色Leaf:在组合中表示叶节点对象——没有子节点,实现抽象构件角色声明的接口。
树枝构件角色Composite:在组合中表示分支节点对象有子节点,实现抽象构件角色声明的接口;存储子部件。
透明性还是安全性:
组合模式中必须提供对子对象的管理方法,不然无法完成对子对象的添加删除等等操作,也就失去了灵活性和扩展性。但是管理方法是在Component中就声明还是在Composite中声明呢?
一种方式是:在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化。目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。但树叶是不存在子类的,因此Component声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。
另一种方式就是:只在Composite里面声明所有的用来管理子类对象的方法。这样就避免了上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。
《设计模式》一书认为:在这一模式中,相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。最终我们选择透明性。
组合模式优点:
高层模块调用简单:树形机构中所有节点都是Component,高层模块不必关心自己处理的是单个对象还是整个组合结构,简化了高层模块的代码
更容易在组合体内加入对象部件. 客户端不必因为加入了新的对象部件而更改代码。这一点符合开闭原则的要求,对系统的二次开发和功能扩展很有利,我们需要的构件可以直接在叶子节点加入
节点自由增加:容易扩展,符合OCP,对维护有利
组合模式的缺点:
有利必有弊,视需求而定:组合模式不容易限制组合中的构件,叶子节点可能会实现其他的方法。
叶子节点的数量可能会很多。
组合模式的使用场景:
维护和展示部分-整体关系的场景,如树形菜单、文件和文件夹管理
当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了。
从一个整体中能够独立出部分模块或功能的场景
注意事项:
Operation()函数可以配合迭代器模式一起使用。
组合模式的例子:会员卡消费
首先:
1.我们的部件有,总店,分店,加盟店!
2.我们的部件共有的行为是:刷会员卡
3.部件之间的层次关系,也就是店面的层次关系是,总店下有分店、分店下可以拥有加盟店。
有了我们这几个必要条件后,我的要求就是目前店面搞活动当我在总店刷卡后,就可以累积相当于在所有下级店面刷卡的积分总额,设计的代码如下:
类图:
总店:抽象类,提供统一操作:
分店:下面可以有加盟店
加盟店:叶子节点,下面不可以有其他分店
实现场景:
运行结果:
这样在累积所有子店面积分的时候,就不需要去关心子店面的个数了,也不用关系是否是叶子节点还是组合节点了,也就是说不管是总店刷卡,还是加盟店刷卡,都可以正确有效的计算出活动积分。