装饰者模式(Decorator Pattern)

一、装饰者模式的内容


装饰(Decorator)模式又名包装(Wrapper)模式[GOF95]。装饰者模式动态地将责任附加到对象上。想要扩展功能,装饰者提供有别于继承的另一种选择。该模式以对客户端透明的方式扩展对象的功能。利用组合在运行时动态的合成自己想要的对象,这比继承更具弹性,是继承关系的一个替代方案。

二、装饰者模式的结构

涉及角色

(1)抽象构件角色:定义一个抽象接口,来规范准备附加功能的类。

(2)具体构件角色(即被装饰者):将要被附加功能的类,实现抽象构件角色接口。

(3)抽象装饰者角色:持有对具体构件角色的引用并定义与抽象构件角色一致的接口。

(4)具体装饰角色:实现抽象装饰者角色,负责为具体构件添加额外功能。

其中,被装饰者与抽象装饰者都继承与抽象构件角色,具体装饰角色继承与抽象装饰角色,之所以让装饰者和被装饰者继承于同一组件是想让装饰者和被装饰者具有统一的类型而非为了继承行为。

装饰者模式的基本思想是用装饰者来包装组件使之成为一个同类型的新组件,所以在装饰者角色中,记录当前对象(一般是声明一个基类引用变量,构造器中传对象引用参数初始化此变量),利用多态技术,用基类对象引用最终被包裹后的对象(注意:每包裹一层就把之前的对象覆盖掉),就获得了组件和所有包裹过组件的行为。

三、要点

  • 继承属于扩展的形式之一,但不见得是达到弹性设计的最佳方式。(子类数量爆炸、设计死板、以及基类加入的新功能并不能适用与所有子类。)

  • 在我们的设计中,应该允许行为可以被扩展,而无须修改现有的代码。

  • 组合和委托可以再运行时动态地加上新的行为。

  • 除了继承,装饰者模式也可以让我们扩展行为。

  • 装饰者模式意味着一群装饰者类,这些类用来包装具体组件。

  • 装饰者类反应被装饰的组件的类型

  • 装饰者可以再被装饰者的行为前面与/或后面加上自己的行为,甚至将被装饰者的行为整个去掉,而达到特性行为的目的。

  • 你可以用无数个装饰者包装一个组件。

  • 装饰者一般对组件的客户是透明的,除非客户依赖于组件的具体类型。

  • 装饰者会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。

  • 装饰者和被装饰对象有相同的超类型。

四、装饰者模式当中OO原则

  • 封装变化

  • 多用组合,少用继承

  • 针对接口编程,不针对实现编程

  • 交互对象之间的松耦合设计而努力

  • 对扩展开放,对修改关闭

五、装饰者模式示例代码

代码一、

[java] view plaincopy

  1. // the Window interface

  2. interface Window {

  3. public void draw(); // draws the Window

  4. public String getDescription(); // returns a description of the Window

  5. }
  6. // implementation of a simple Window without any scrollbars

  7. class SimpleWindow implements Window {

  8. public void draw() {

  9. // draw window

  10. }
  11. public String getDescription() {

  12. return "simple window";

  13. }

  14. }

[java] view plaincopy

  1. // abstract decorator class - note that it implements Window

  2. abstract class WindowDecorator implements Window {

  3. protected Window decoratedWindow; // the Window being decorated
  4. public WindowDecorator (Window decoratedWindow) {

  5. this.decoratedWindow = decoratedWindow;

  6. }

  7. public void draw() {

  8. decoratedWindow.draw();

  9. }

  10. }
  11. // the first concrete decorator which adds vertical scrollbar functionality

  12. class VerticalScrollBarDecorator extends WindowDecorator {

  13. public VerticalScrollBarDecorator (Window decoratedWindow) {

  14. super(decoratedWindow);

  15. }
  16. public void draw() {

  17. decoratedWindow.draw();

  18. drawVerticalScrollBar();

  19. }
  20. private void drawVerticalScrollBar() {

  21. // draw the vertical scrollbar

  22. }
  23. public String getDescription() {

  24. return decoratedWindow.getDescription() + ", including vertical scrollbars";

  25. }

  26. }
  27. // the second concrete decorator which adds horizontal scrollbar functionality

  28. class HorizontalScrollBarDecorator extends WindowDecorator {

  29. public HorizontalScrollBarDecorator (Window decoratedWindow) {

  30. super(decoratedWindow);

  31. }
  32. public void draw() {

  33. decoratedWindow.draw();

  34. drawHorizontalScrollBar();

  35. }
  36. private void drawHorizontalScrollBar() {

  37. // draw the horizontal scrollbar

  38. }
  39. public String getDescription() {

  40. return decoratedWindow.getDescription() + ", including horizontal scrollbars";

  41. }

  42. }

[java] view plaincopy

  1. public class DecoratedWindowTest {

  2. public static void main(String[] args) {

  3. // create a decorated Window with horizontal and vertical scrollbars

  4. Window decoratedWindow = new HorizontalScrollBarDecorator (

  5. new VerticalScrollBarDecorator(new SimpleWindow()));
  6. // print the Window‘s description

  7. System.out.println(decoratedWindow.getDescription());

  8. }

  9. }

代码二、

[java] view plaincopy

  1. public abstract class Beverage {

  2. String description = "Unknown Beverage";
  3. public String getDescription() {

  4. return description;

  5. }
  6. public abstract double cost();

  7. }

[java] view plaincopy

  1. public abstract class CondimentDecorator extends Beverage {

  2. public abstract String getDescription();

  3. }

[java] view plaincopy

  1. public class DarkRoast extends Beverage {

  2. public DarkRoast() {

  3. description = "Dark Roast Coffee";

  4. }
  5. public double cost() {

  6. return .99;

  7. }

  8. }

[java] view plaincopy

  1. public class Decaf extends Beverage {

  2. public Decaf() {

  3. description = "Decaf Coffee";

  4. }
  5. public double cost() {

  6. return 1.05;

  7. }

  8. }

[java] view plaincopy

  1. public class Espresso extends Beverage {
  2. public Espresso() {

  3. description = "Espresso";

  4. }
  5. public double cost() {

  6. return 1.99;

  7. }

  8. }

[java] view plaincopy

  1. public class HouseBlend extends Beverage {

  2. public HouseBlend() {

  3. description = "House Blend Coffee";

  4. }
  5. public double cost() {

  6. return .89;

  7. }

  8. }

[java] view plaincopy

  1. public class Milk extends CondimentDecorator {

  2. Beverage beverage;
  3. public Milk(Beverage beverage) {

  4. this.beverage = beverage;

  5. }
  6. public String getDescription() {

  7. return beverage.getDescription() + ", Milk";

  8. }
  9. public double cost() {

  10. return .10 + beverage.cost();

  11. }

  12. }

[java] view plaincopy

  1. public class Mocha extends CondimentDecorator {

  2. Beverage beverage;
  3. public Mocha(Beverage beverage) {

  4. this.beverage = beverage;

  5. }
  6. public String getDescription() {

  7. return beverage.getDescription() + ", Mocha";

  8. }
  9. public double cost() {

  10. return .20 + beverage.cost();

  11. }

  12. }

[java] view plaincopy

  1. public class Soy extends CondimentDecorator {

  2. Beverage beverage;
  3. public Soy(Beverage beverage) {

  4. this.beverage = beverage;

  5. }
  6. public String getDescription() {

  7. return beverage.getDescription() + ", Soy";

  8. }
  9. public double cost() {

  10. return .15 + beverage.cost();

  11. }

  12. }

[java] view plaincopy

  1. public class Whip extends CondimentDecorator {

  2. Beverage beverage;
  3. public Whip(Beverage beverage) {

  4. this.beverage = beverage;

  5. }
  6. public String getDescription() {

  7. return beverage.getDescription() + ", Whip";

  8. }
  9. public double cost() {

  10. return .10 + beverage.cost();

  11. }

  12. }

[java] view plaincopy

  1. public class StarbuzzCoffee {
  2. public static void main(String args[]) {

  3. Beverage beverage = new Espresso();

  4. System.out.println(beverage.getDescription()

  5. + " $" + beverage.cost());
  6. Beverage beverage2 = new DarkRoast();

  7. beverage2 = new Mocha(beverage2);

  8. beverage2 = new Mocha(beverage2);

  9. beverage2 = new Whip(beverage2);

  10. System.out.println(beverage2.getDescription()

  11. + " $" + beverage2.cost());
  12. Beverage beverage3 = new HouseBlend();

  13. beverage3 = new Soy(beverage3);

  14. beverage3 = new Mocha(beverage3);

  15. beverage3 = new Whip(beverage3);

  16. System.out.println(beverage3.getDescription()

  17. + " $" + beverage3.cost());

  18. }

  19. }

六、 使用装饰模式的优点和缺点


使用装饰模式主要有以下的优点:

  1. 装饰模式与继承关系的目的都是要扩展对象的功能,但是装饰模式可以提供比继承更多的灵活性。

  2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。

  3. 这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错。

使用装饰模式主要有以下的缺点:

由于使用装饰模式,可以比使用继承关系需要较少数目的类。使用较少的类,当然使设计比较易于进行。但是,在另一方面,使用装饰模式会产生比使用继承关系更多的对象。更多的对象会使得查错变得困难,特别是这些对象看上去都很相像。

七、 模式实现的讨论

大多数情况下,装饰模式的实现都比上面定义中给出的示意性实现要简单。对模式进行简化时需要注意以下的情况:

(1)一个装饰类的接口必须与被装饰类的接口相容。

(2)尽量保持Component作为一个"轻"类,不要把太多的逻辑和状态放在Component类里。

(3)如果只有一个ConcreteComponent类而没有抽象的Component类(接口),那么Decorator类经常可以是ConcreteComponent的一个子类。如下图所示:

(4)如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。

八、装饰者模式在JDK当中应用

Decorator (recognizeable
by creational methods taking an instance
of same abstract/interface type which adds additional
behaviour)



九、参考文献

1、http://en.wikipedia.org/wiki/Decorator_pattern

2、http://blog.csdn.net/rocket5725/article/details/4327497

3、《head first 设计模式》

4、http://stackoverflow.com/questions/1673841/examples-of-gof-design-patterns

转:http://blog.csdn.net/yangzl2008/article/details/7643395

装饰者模式(Decorator Pattern),布布扣,bubuko.com

时间: 2024-11-03 03:46:59

装饰者模式(Decorator Pattern)的相关文章

设计模式 - 装饰者模式(Decorator Pattern) Java的IO类 使用方法

装饰者模式(Decorator Pattern) Java的IO类 使用方法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26716823 装饰者模式(decorator pattern)参见: http://blog.csdn.net/caroline_wendy/article/details/26707033 Java的IO类使用装饰者模式进行扩展, 其中FilterInputStream类, 就是装饰者(decora

设计模式 - 装饰者模式(Decorator Pattern) 详解

装饰者模式(Decorator Pattern) 详解 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26707033 装饰者模式(Decorator Pattern):动态地将责任附加到对象上. 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案. 使用方法: 1. 首先创建组件(Component)父类, 所有类,具体组件(Concrete Component)和装饰者(Decorator)都属于这一类型, 可以进行扩展

设计模式 - 装饰者模式(Decorator Pattern) 具体解释

装饰者模式(Decorator Pattern) 具体解释 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26707033 装饰者模式(Decorator Pattern):动态地将责任附加到对象上. 若要扩展功能, 装饰者提供了比继承更有弹性的替代方案. 用法: 1. 首先创建组件(Component)父类, 全部类,详细组件(Concrete Component)和装饰者(Decorator)都属于这一类型, 能够进行扩展

设计模式 - 装饰者模式(Decorator Pattern) Java的IO类 用法

装饰者模式(Decorator Pattern) Java的IO类 用法 本文地址: http://blog.csdn.net/caroline_wendy/article/details/26716823 装饰者模式(decorator pattern)參见: http://blog.csdn.net/caroline_wendy/article/details/26707033 Java的IO类使用装饰者模式进行扩展, 当中FilterInputStream类, 就是装饰者(decorato

例说装饰者模式(Decorator Pattern)

前言 装饰者模式在餐饮行业有着比较广泛的应用,网上大部分关于该模式的例子都和饮食相关,以前看译制片电影,每当看到老外们在咖啡店一口流利的点咖啡要加糖要加奶昔要加这加那的时候,感觉好有派~好高大上啊~,为啥我在小卖部都是"来瓶汽水"就没话说了呢~,难道是我不会"装"? 官方定义 动态的给一个对象添加一些职责,就增加功能来说,该模式比生成子类更为灵活--GOF Decorator模式是一种相对简单的对象结构性模式,动态和对象是个对应的关系,正如静态和类这样的对应关系,编

设计模式(结构型)之装饰者模式(Decorator Pattern)

PS一句:最终还是选择CSDN来整理发表这几年的知识点,该文章平行迁移到CSDN.因为CSDN也支持MarkDown语法了,牛逼啊! [工匠若水 http://blog.csdn.net/yanbober] 阅读前一篇<设计模式(结构型)之组合模式(Composite Pattern)>http://blog.csdn.net/yanbober/article/details/45392513 概述 装饰模式可以在不改变一个对象本身功能的基础上给对象增加额外的新行为.装饰模式是一种用于替代继承

23种设计模式之装饰器模式(Decorator Pattern)

装饰器模式(Decorator Pattern) 允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能. 通过采用组合.而非继承的手法,Decorator模式实现了在运行时动态地扩展对象功能的能力,而且可以根据需要扩展多个功能.避免了单独使用继承带来的“灵活性差"和"多子类衍生问题". 优点:装饰类和被装饰类可以独立发

Android设计模式之中的一个个样例让你彻底明确装饰者模式(Decorator Pattern)

导读 这篇文章中我不会使用概念性文字来说明装饰者模式.由于通常概念性的问题都非常抽象.非常难懂.使得读者非常难明确究竟为什么要使用这样的设计模式.我们设计模式的诞生,肯定是前辈们在设计程序的时候遇到了某种困难,为了避免这样的苦难的发生,从而设计出来的这样的设计模式,所以这篇文章中我会带领大家遇见这样的困难,从而使用设计模式解决这样的困难,最后大家就会明确什么是设计者模式,什么时候应该使用设计者模式以及怎样使用设计者模式了 首先我们先来看一下装饰者模式的UML图是什么样子的.图中各个类的含义不懂没

9.装饰者模式(Decorator Pattern)

using System; namespace ConsoleApplication7 { class Program { static void Main(string[] args) { // 我买了个苹果手机 Phone phone = new ApplePhone(); // 现在想贴膜了 Decorator applePhoneWithSticker = new Sticker(phone); // 扩展贴膜行为 applePhoneWithSticker.Print(); Conso

用最简单的例子理解装饰器模式(Decorator Pattern)

假设有一个公司要做产品套餐,即把不同的产品组合在一起,不同的组合对应不同的价格.最终呈现出来的效果是:把产品组合的所有元素呈现出来,并显示该组合的价格. 每个产品都有名称和价格,首先设计一个关于产品的抽象基类. public abstract class ProductBase { public abstract string GetName(); public abstract double GetPrice(); } 所有的产品都必须继承这个基类,比如家居用品.电器产品等,把这些具体的产品提