1. 意图
动态地给一个对象添加一些额外的职责。就增加功能来说,Decorator模式比生成子类更为灵活。
2. 别名
包装器 Wrapper
3. 动机
给某个对象而不是整个类添加一些功能。
4. 适用性
在不影响其他对象的情况下,以动态,透明的方式给单个对象添加职责。
处理那些可以撤销的职责。
当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
5. 类图
6. 代码
class Program { static void Main(string[] args) { IWindow window = new HorizontalScrollbarDecorator(new VerticalScrollbarDecorator(new SimpleWindow())); window.Draw(); } } interface IWindow { void Draw(); string GetDescription(); } class SimpleWindow : IWindow { public void Draw() { Console.WriteLine("draw a simple window"); } public string GetDescription() { return "I am a simple window"; } } class WindowDecorator : IWindow { protected IWindow iWindow = null; public WindowDecorator(IWindow iWindow) { this.iWindow = iWindow; } public void Draw() { iWindow.Draw(); } public string GetDescription() { return iWindow.GetDescription(); } } class HorizontalScrollbarDecorator : WindowDecorator { public HorizontalScrollbarDecorator(IWindow iWindow) : base(iWindow) { } public void Draw() { base.Draw(); DrawHorizontalScrollbarDecorator(); } private void DrawHorizontalScrollbarDecorator() { Console.WriteLine("draw a horizontal scrollbar"); } public string GetDescription() { string result = base.GetDescription(); result += "a window with horizontal scrollbar"; return result; } } class VerticalScrollbarDecorator : WindowDecorator { public VerticalScrollbarDecorator(IWindow iWindow) : base(iWindow) { } public void Draw() { base.Draw(); DrawVerticalScrollbarDecorator(); } private void DrawVerticalScrollbarDecorator() { Console.WriteLine("draw a vertical scrollbar"); } public string GetDescription() { string result = base.GetDescription(); result += "a window with vertical scrollbar"; return result; } }
8. 效果
Decorator模式的优点和缺点
1) 比静态继承更灵活
2) 可以避免在层次结构的高层类有太多的特性
3) Decorator类和Component类还是不一样的
4) 太多的Decorator容易产生很多小对象
9. 讨论
Decorator可以在运行时为对象动态的添加职责,关键点就在于Decorator与ConcreteComponen具有同样的接口
Decorator和Composite模式的区别在于Composite模式的一个类具有容器的特性,因此可以体现部分-整体的关系, 并且没有子类
Decorator的装饰类可以有子类,子类就是具体的装饰者
公共的Component应当尽量保持简单,它应当集中于定义接口而不是存储数据