为什么会有组合模式?
很多场景能够抽象为树状结构
树有节点,节点分为根节点、树枝节点、叶子节点。
根节点和树枝节点因为能够包含其他树枝节点或叶子节点,故抽象为复合节点。
客户端操作:添加节点、删除节点、修改节点、打印树、对节点的某些属性进行统计
此时出现问题:
对开发者来说:
问题1:
复合节点可以包含子复合节点和叶子节点 在复合类中,要设置两个集合,> 一个存储存储它所包含的子复合节点> ,一个存储存储它所包含的叶子节点 此时,如果在逻辑上要对其下的所有节点做> 统一的操作 在程序中需要先对它包含的> 子复合节点> 做操作,再对它包含的> 叶子节点> 做同样的操作这样就会> 冗余> 。 功能扩展不方便——每个功能都要写两遍,代码冗余。 不符合依赖倒置原则。 问题2: 要新增一种只能包含叶子节点的节点 复合类中又需要增加一个集合来存储这种节点 对所有的节点做统一操作的代码中也要加入对这种节点的操作 更改了以前的代码,不符合开闭原则。
对于客户端:
问题3:
需要详细了解每种类的方法: 比如:复合类中打印名字的方法叫print()方法,叶子类中同样的功能也是叫print()吗?研究一下源码,这样客户端调用太复杂了。 不符合依赖倒置原则。
组合模式的实现
将复合节点和叶子节点中方法的并集做成接口。两个类分别重写这些接口即可。
组合模式实现之后的好处
- 组合类中,只需要一个collection对象即可存所有的节点类型
- 组合类中,递归操作所有对象做一个操作时,可以使用抽象类中的所有双方都有的基础方法
- 客户端只需要知道抽象接口中的方法即可使用所有节点对象
组合模式的缺点
复合节点类(Composite)和叶子节点类(Leaf)都继承了抽象类(Component)
客户端只能看到抽象类(Component)中的方法,但是不知道复合类实现了那些方法,叶子类又实现了那些方法,导致,使用多态时,如果对象调用的方法没有实现,只能在运行时才能抛出运行时异常。给代码调用带来不便。
