师说
树形结构不论在生活中或者是开发中都是一种非常常见的结构,一个容器对象(如文件夹)下可以存放多种不同的叶子对象或者容器对象,容器对象与叶子对象之间属性差别可能非常大。组合模式为解决此类问题而诞生,它可以让叶子对象和容器对象的使用具有一致性。而组合模式的使用场景就是出现树形结构的地方。比如:文件目录显示,多及目录呈现等树形结构数据的操作。比如:Swing中,Button、Checkbox等组件都是树叶,而Container容器是树枝;比如:文本编辑时,可以单个字编辑,也可以整段编辑,还可以全文编辑;文件复制时,可以一个一个文件复制,也可以整个文件夹复制等等情况。
下面我们以公司的层级结构为例,(选自《大话设计模式》)。
这幅图表示的是部分与整体的关系,因此我们就可以考虑使用组合模式。另外,细细分析图中的结构与组成,我们可以得出以下UML图:
组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。
也可以看我大三以前的上这门课时的博客:
组合模式
案例:公司的人事管理,就是领导与被领导。
根据这个人事图,最先设计的 UML 图是:
有没有发现,接口里有好多方法重复了呢?
改进版的 UML 看起来很不错额,最起码干掉了一个 IRoot 接口,整个类图看起来简洁很多而且方法也不重复,但仔细看看,真的改好了吗?
现在我们能理解了吧,上一个类图中 ILeaf 接口中的 getInfo() 方法有重大的嫌疑,你再回去仔细瞧瞧
那现在这个类图行了吗?这个时候我们的理解一下接口的作用了:
接口的作用:定义共性,凡是其他接口有的,另一个接口就没必要重复了。
上一图中 ICop 中 getInfo() 是不是和 IBranch 中的 getSubordinateInfo() 功能上重复了,所以还得改,最终才有这个版本的类图。
也许你已经发现,怎么和文章中的第一个图那么相似呢?
对的,这个就是组合模式图了,也就是说,如果你把自己的项目优化优化,也许不知不觉中就在使用了组合模式。
组合模式的几个角色:
- 抽象构件(Component):定义参加组合的对象的共有方法和属性,可以定义一些默认的行为或属性,比如 getInfo
- 叶子构件(Leaf):叶子对象,其下没有分支。
- 树枝构件(Composit):树枝对象,它的作用是组合树枝节点和叶子节点。
组合的适用场合:
- 你想表示对象的部分 - 整体层次结构。
- 你希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象
优点:
- 组合模式可以很容易的增加新的构件。
- 使用组合模式可以使客户端变的很容易设计,因为客户端可以对组合和叶节点一视同仁。
缺点:
- 使用组合模式后,控制树枝构件的类型不太容易。
- 用继承的方法来增加新的行为很困难。
PS:如果不太明白组合是什么,可以先了解一下组合与继承
装饰模式
定义
装饰模式(Decorator)动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式比生成子类更加灵活。
这里可以举一个生活中的例子,一个蛋糕,在蛋糕上摆上水果,这个蛋糕就变成了水果蛋糕,给这个水果蛋糕插上蜡烛,它就变成了一个生日蛋糕。(这是Head First中的一个例子,个人觉得非常的形象,记忆犹新)。
分析
如果我们需要扩展一个类的功能,你会怎么做呢?如果直接修改这个类,我们就违反了开闭原则(对修改关闭,对扩展开放)。
我们可以继承这个类,写一个这个类的子类,用于实现扩展功能,也可以使用组合(将这个类作为成员变量),达到相同的效果。
我们将继承这种关系称为is-a,组合这种关系称为use-a。is-a的耦合程度要高于use-a,所以我们经常可以听到这样的说法:组合优于继承,原因就是这两种关系的耦合程度不同。
装饰模式的核心思想,其实就是用组合代替继承。
图解
这里可以看出,装饰者模式的特点是,装饰者实现了被装饰对象的接口,同时又将被装饰对象作为了成员变量
实例
这里举一个咖啡店的例子,咖啡的原料是咖啡豆,我们可以使用咖啡豆和牛奶、蜂蜜、摩卡组合出不同价格、不同口味的咖啡。
这里咖啡豆就是被装饰的对象,也就是图示中的ConcreteComponent,饮品类就是我们抽象出的Component,定义了展示价格和材料两个方法。牛奶、蜂蜜、摩卡是装饰对象,也就是图中的ConcreteDecoratorA、ConcreteDecoratorB。他们抽象出的Decorator,同样定义了展示价格和材料两个方法,具体类图与实现如下:
代码
1 | /** |
1 | /** |
1 | /** |
1 | /** |
1 | /** |
1 | /** |
1 | /** |
1 | /** |
结果:
1 | 第一种咖啡豆加蜂蜜加摩卡 |