复合模式和装饰器模式有什么区别?
7 回答
复合模式和装饰器的结构看起来相同,但它们的意图不同。
Composite为叶和复合提供了统一的接口。
装饰器装饰器为叶子提供了附加功能,同时提供了统一的界面。
例子
复合模式:经典的 windows 文件夹和文件。Windows 文件夹是复合的。文件是叶子。双击其中任何一个打开文件/文件夹 - 双击是统一界面。
装饰器模式:缓冲 io -java.io.FileWriter
并且java.io.BufferedWriter
都扩展java.io.Writer
。java.io.BufferedWriter
是复合的并且FileWriter
是叶子。BufferedWriter
将缓冲的额外责任(或功能)添加到FileWriter
.
write()
方法是统一接口,而缓冲是附加功能。
他们通常齐头并进。因为使用复合模式通常会导致也使用装饰器模式。
复合模式允许您以允许外部代码将整个结构视为单个实体的方式构建层次结构(例如元素树)。因此,叶实体的接口与复合实体的实体完全相同。所以本质是复合结构中的所有元素都具有相同的接口,即使有些是叶节点而另一些是整个结构。用户界面经常使用这种方法来实现简单的可组合性。
http://en.wikipedia.org/wiki/Composite_pattern
装饰器模式允许一个实体完全包含另一个实体,以便使用装饰器看起来与包含的实体相同。这允许装饰器在不改变实体外观的情况下修改它所封装的任何内容的行为和/或内容。例如,您可以使用装饰器在包含元素的使用情况下添加日志输出,而不会更改包含元素的任何行为。
装饰器可以被视为只有一个组件的退化组合。然而,装饰器增加了额外的职责——它不适合对象聚合。
这就是四人组在“可重用面向对象软件的设计模式-元素”中所说的。
差异可能更多是目的而不是实施。在某些情况下,复合模式比子类化更可取。例如,您可以通过向其添加其他类的实例然后通过转发接口公开该功能来添加您希望类具有的功能。
装饰器允许您透明地向类添加功能,通常是单个功能,而类实例的客户端不需要知道那里有装饰器 - 例如,Django 中视图上的“login_required”装饰器会引发异常如果用户未登录,否则视图的行为与没有装饰器时一样。
在这两种情况下,您都将一个对象嵌入到另一个对象中,但是您要完成的工作可以说是不同的。
装饰器模式可用于静态扩展(装饰)某个对象的功能,或者在某些情况下在运行时独立于同一类的其他实例。
这可能是由于组合:装饰器包含组件,同时它实现了组件接口。
复合模式描述了一组对象以与对象的单个实例相同的方式处理。组合的目的是将对象“组合”成树结构以表示部分整体的层次结构。
实现复合模式可以让客户统一处理单个对象和组合。
尽管结构似乎相同,但意图和用例却不同。
装饰器模式的用例:
- 应动态添加/删除对象职责和行为
- 具体的实现应该与责任和行为脱钩
- 子类化成本太高,无法动态添加/删除职责
这两种模式之间的主要区别:
- 装饰器旨在让您无需子类化就可以向对象添加职责。Composite的重点不是装饰而是表现
- 装饰器添加/删除额外的职责——它不是用于对象聚合的。
SE中有用的帖子可以更好地理解:
结构差异
以下是使用 PlantUML 复制的 GoF 书中的类图。
意图差异
Decorator 的目的是装饰单个组件(UML 图实际上应该为被装饰的组件显示一个多重性),而 Composite 的目的是在 Composite 中将组件作为一个整体进行分组(同样,UML 应该显示一个包含一种或多种成分的复合材料)。
Decorator 的目标是通过 ConcreteDecorators 添加行为(增强Operation()
方法的行为),而 Composite 旨在收集组件。
合成的:
- 是使用递归的树结构。
- Leaf 和 Composite 具有相同的接口
- 对象之间的统一
装饰器:
- 是否包含另一个实体。
- 在不修改复合对象的情况下向复合对象添加新功能。