设计模式(九)组合模式

组合模式属于结构型模式的一种。

首先试想一个问题:

需要开发一个杀毒软件针,可以针对文件夹(Folder)和不同的文件类型(Text、Video、Img等)进行不同方式的杀毒

通常情况下,最简单的实现如下图:

上图需要实现多个不同的文件类型以及对应的killVirus方法,同时还要在文件夹类中维护多种文件类型的集合来表示子类,假如需要加入MovieFile就必须对Folder进行修改(添加集合变量、修改killVirus递归实现),不符合开闭原则,代码灵活性差。

再提出另外一个类似的问题,并解决该问题:

开发一个界面控件库,界面控件分为两大类,一类是单元控件,例如按钮、文本框等,一类是容器控件,例如窗体、中间面板等,试用组合模式设计该界面控件库

问题需要开发两种类型的控件,如果能够把所有类型控件的共同特征进行提取和抽象,我们就能很方便的对所有控件进行统一操作,所以我们定义一个Widget抽象类;接着是单元控件,单元控件没有子控件;最后是容器控件,容器控件可能会有子控件。

根据上图的设计方法,今后增加任何新类型的控件,都不需要对原有的容器控件进行修改,而且容器控件的show()方法中可以递归调用所有子控件的show(),而不用根据子控件类型进行区别处理,这就是组合模式的基本用法

透明组合和安全组合:

继续扩展上面的问题,上面在Widget中定义了一个addSub()用于增加新的子控件,但是单元控件不能正常执行addSub方法,所以需要在实现类或Widget中进行错误提示,或者也可以采取另一种方式:将Widget中的addSub()移除,这时只需要在容器控件中实现addSub()即可。这两种方式分别成为透明组合和安全组合

透明组合的缺陷是不够安全,而安全组合的缺陷是不能对子构件进行统一操作。

总结:

组合模式通过一种巧妙的设计方案使得用户可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致性地处理树形结构中的叶子节点和容器节点。

优点

  1. 符合开闭原则,新增构件不影响原有代码
  2. 可以忽略层次差异,方便对层次结构的控制
  3. 支持复杂的树机构,但对树结构的控制非常简单

缺点

  1. 难以对构件类型进行控制,比如某个容器控件仅允许指定类型的子控件,实现较复杂