1.说明:
composite模式是一种帮我们解决结构分层和统一抽象的解决方案。所谓的结构分层指原型跟原型组合的关系,而统一抽象是指原型跟组合之间的能够抽象一致。
在gof的书中也有一个比较好的例子,那就是画图,他们把单个图形(点、线、矩形等)作为原型,然后把由单个图形组成的行或者一个表格看成是原型的组合,但是原型及其组合都可以统一抽象成一个组件。通过这种方式,用于展现的代码调用就无需区分具体是单个原型还是组合,只需要依赖于抽象组件的动作即可。
个人没参与过这种例子,但是也从gof的这个例子中了解了大部分的抽象。但是,还是想自己找个现实中的例子来看看。
如果你没玩过,可以通过淘宝去定一盒,发挥你的想象力,你可以用那么几十个小组件拼成多少个美丽的模具。
如这个小图中的每个组件,我觉得可以想象成composite中的primitive objects,用一个个小组件合成的就是一个组合,然后完成整个小模具,就是各个可以看成是组合之间的结合。对我们玩的人来说,一个小组件和插在一起的组件都是一样的,只不过是一个实现了更加多的功能,但是都是统一的穿插接口。
所以,在composite模式中,我们需要去挖掘这么几个东西:
统一的组件抽象(至少是动作抽象,就像塑料积木中的插口);
原型(单个小组件,如塑料积木中的一个小模块)和建立在原型上的组合;
调用的客户端(这个不用太去纠结,实际可以想象成玩积木的人)。
对应的类图如下(我又偷了一下懒,从gof的design patterns中借用一下):
按照上面的顺序,我们首先要看到,受益最大的是客户端,因为它不需要知道任何关于原型和组合的具体实现,它仅仅依赖于component接口,但是却可以实现功能的扩展。这个时候我们可以用ocp原则来检测一下:对功能的扩展开放,对架构的变更关闭。这个非常适合。
2.对比一下:
既然如此,那么composite模式的方式好像跟proxy模式和chain of responsibility很相似呀?
composite的特点是“部分-整体”关系,也就是说,从结构角度讲,这个整体也是由这些部分组成的。而调用方,可以一致性的对待部分和整体,无需关心到底是部分还是整体。
proxy是为了隔离调用方和实现方而架设的,它没有部分-整体的关系。客户端依赖于proxy实现,而proxy 封装了具体实现。它的“三角关系”比较清晰一些;
chain of responsibility的确跟composite挺像,但是它着重于在chain中的每个业务处理,直接面向客户端调用的不是一个统一的接口,而是一个具体的组件,每个组件之间有关联,同时每个组件要针对request做出相应的处理工作(这就是对应的responsibility)。
3.思考一下:
这个模式有啥弊端呢?
既然客户端仅仅依赖于component,而且primitive objects 和composed objects都实现了component接口,那么鉴于这两种实现方式的动作,可能会导致component接口出现违反isp原则的情况,从而使得一些集合操作的动作也抽象到接口中,而每个primitive object要去实现没意义的方法,这里可以考虑使用null object设计模式来避免。
既然每个primitive object都是基本组件,组合也是由基本组件组成,我们也可以考虑引入一些缓存机制来实现基本组件的缓存。