装饰模式的定义与特点

装饰(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式。

装饰(Decorator)模式的主要优点有:

  • 采用装饰模式扩展对象的功能比采用继承方式更加灵活。
  • 可以设计出多个不同的具体装饰类,创造出多个不同行为的组合。

其主要缺点是:装饰模式增加了许多子类,如果过度使用会使程序变得很复杂。

装饰模式的结构与实现

通常情况下,扩展一个类的功能会使用继承方式来实现。但继承具有静态特征,耦合度高,并且随着扩展功能的增多,子类会很膨胀。如果使用组合关系来创建一个包装对象(即装饰对象)来包裹真实对象,并在保持真实对象的类结构不变的前提下,为其提供额外的功能,这就是装饰模式的目标。下面来分析其基本结构和实现方法。

1. 模式的结构

装饰模式主要包含以下角色。

  1. 抽象构件(Component)角色:定义一个抽象接口以规范准备接收附加责任的对象。
  2. 具体构件(Concrete    Component)角色:实现抽象构件,通过装饰角色为其添加一些职责。
  3. 抽象装饰(Decorator)角色:继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能。
  4. 具体装饰(ConcreteDecorator)角色:实现抽象装饰的相关方法,并给具体构件对象添加附加的责任。

装饰模式的结构图如图 1 所示。


图1 装饰模式的结构图

2. 模式的实现

装饰模式的实现代码如下:

 
  1. package decorator;
    public class DecoratorPattern
    {
    public static void main(String[] args)
    {
    Component p=new ConcreteComponent();
    p.operation();
    System.out.println("---------------------------------");
    Component d=new ConcreteDecorator(p);
    d.operation();
    }
    }
    //抽象构件角色
    interface Component
    {
    public void operation();
    }
    //具体构件角色
    class ConcreteComponent implements Component
    {
    public ConcreteComponent()
    {
    System.out.println("创建具体构件角色");
    }
    public void operation()
    {
    System.out.println("调用具体构件角色的方法operation()");
    }
    }
    //抽象装饰角色
    class Decorator implements Component
    {
    private Component component;
    public Decorator(Component component)
    {
    this.component=component;
    }
    public void operation()
    {
    component.operation();
    }
    }
    //具体装饰角色
    class ConcreteDecorator extends Decorator
    {
    public ConcreteDecorator(Component component)
    {
    super(component);
    }
    public void operation()
    {
    super.operation();
    addedFunction();
    }
    public void addedFunction()
    {
    System.out.println("为具体构件角色增加额外的功能addedFunction()");
    }
    }
    

    程序运行结果如下:

创建具体构件角色
调用具体构件角色的方法operation()
---------------------------------
调用具体构件角色的方法operation()
为具体构件角色增加额外的功能addedFunction()

装饰模式的应用实例

【例1】用装饰模式实现游戏角色“莫莉卡·安斯兰”的变身。

分析:在《恶魔战士》中,游戏角色“莫莉卡·安斯兰”的原身是一个可爱少女,但当她变身时,会变成头顶及背部延伸出蝙蝠状飞翼的女妖,当然她还可以变为穿着漂亮外衣的少女。这些都可用装饰模式来实现,在本实例中的“莫莉卡”原身有 setImage(String t) 方法决定其显示方式,而其 变身“蝙蝠状女妖”和“着装少女”可以用 setChanger() 方法来改变其外观,原身与变身后的效果用 display() 方法来显示(点此下载其原身和变身后的图片),图 2 所示是其结构图。


图2 游戏角色“莫莉卡·安斯兰”的结构图

程序代码如下:

 
  1. package decorator;
    import java.awt.*;
    import javax.swing.*;
    public class MorriganAensland
    {
    public static void main(String[] args)
    {
    Morrigan m0=new original();
    m0.display();
    Morrigan m1=new Succubus(m0);
    m1.display();
    Morrigan m2=new Girl(m0);
    m2.display();
    }
    }
    //抽象构件角色:莫莉卡
    interface Morrigan
    {
    public void display();
    }
    //具体构件角色:原身
    class original extends JFrame implements Morrigan
    {
    private static final long serialVersionUID = 1L;
    private String t="Morrigan0.jpg";
    public original()
    {
    super("《恶魔战士》中的莫莉卡·安斯兰");
    }
    public void setImage(String t)
    {
    this.t=t;
    }
    public void display()
    {
    this.setLayout(new FlowLayout());
    JLabel l1=new JLabel(new ImageIcon("src/decorator/"+t));
    this.add(l1);
    this.pack();
    this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    this.setVisible(true);
    }
    }
    //抽象装饰角色:变形
    class Changer implements Morrigan
    {
    Morrigan m;
    public Changer(Morrigan m)
    {
    this.m=m;
    }
    public void display()
    {
    m.display();
    }
    }
    //具体装饰角色:女妖
    class Succubus extends Changer
    {
    public Succubus(Morrigan m)
    {
    super(m);
    }
    public void display()
    {
    setChanger();
    super.display();
    }
    public void setChanger()
    {
    ((original) super.m).setImage("Morrigan1.jpg");
    }
    }
    //具体装饰角色:少女
    class Girl extends Changer
    {
    public Girl(Morrigan m)
    {
    super(m);
    }
    public void display()
    {
    setChanger();
    super.display();
    }
    public void setChanger()
    {
    ((original) super.m).setImage("Morrigan2.jpg");
    }
    }
    

    程序运行结果如图 3 所示。


图3 游戏角色“莫莉卡·安斯兰”的变身

装饰模式的应用场景

前面讲解了关于装饰模式的结构与特点,下面介绍其适用的应用场景,装饰模式通常在以下几种情况使用。

  • 当需要给一个现有类添加附加职责,而又不能采用生成子类的方法进行扩充时。例如,该类被隐藏或者该类是终极类或者采用继承方式会产生大量的子类。
  • 当需要通过对现有的一组基本功能进行排列组合而产生非常多的功能时,采用继承关系很难实现,而采用装饰模式却很好实现。
  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

装饰模式在 Java 语言中的最著名的应用莫过于 Java I/O 标准库的设计了。例如,InputStream 的子类 FilterInputStream,OutputStream 的子类 FilterOutputStream,Reader 的子类 BufferedReader 以及 FilterReader,还有 Writer 的子类 BufferedWriter、FilterWriter 以及 PrintWriter 等,它们都是抽象装饰类。

下面代码是为 FileReader 增加缓冲区而采用的装饰类 BufferedReader 的例子:

 
  1. BufferedReader in=new BufferedReader(new FileReader("filename.txtn));
  2. String s=in.readLine();

装饰模式的扩展

装饰模式所包含的 4 个角色不是任何时候都要存在的,在有些应用环境下模式是可以简化的,如以下两种情况。

(1) 如果只有一个具体构件而没有抽象构件时,可以让抽象装饰继承具体构件,其结构图如图 4 所示。


图4 只有一个具体构件的装饰模式

(2) 如果只有一个具体装饰时,可以将抽象装饰和具体装饰合并,其结构图如图 5 所示。


图5 只有一个具体装饰的装饰模式

5.4结构型模式—————装饰模式相关推荐

  1. 设计模式-结构型模式-装饰模式

    设计模式-结构型模式-装饰模式 栗子 以成绩单需要家长签字为要求. 成绩单类图 // 抽象成绩单 public abstract class SchoolReport{// 成绩单你的成绩情况publ ...

  2. 结构型模式-装饰模式(扩展系统功能)

    目录 1. 定义 2. 结构 3. 代码实现 4. 透明装饰模式与半透明装饰模式 4.1 透明装饰模式 4.2 半透明装饰模式 5. 注意事项 6. 优缺点 7. 适用场景 8. 个人理解 参考 装饰 ...

  3. 结构型模式——装饰模式

    装饰模式的定义与特点 装饰(Decorator)模式的定义:指在不改变现有对象结构的情况下,动态地给该对象增加一些职责(即增加其额外功能)的模式,它属于对象结构型模式. 装饰(Decorator)模式 ...

  4. 【设计模式】结构型模式——装饰模式

    文章目录 一.定义 二.问题 三.解决方案 四.实现 五.UML图 六.装饰模式应用场景 七.总结 优点 缺点 八.与其他模式的关系 一.定义 装饰模式是一种结构型设计模式, 允许你通过将对象放入包含 ...

  5. 10 结构型模式-----装饰模式

    模式动机(Decorator Pattern):我们在给一个类进行功能扩展时,总是通过继承或者复合关系,使得一个类具有其他相关类型的功能,继承本身属于静态关联,派生类比较臃肿,使用者也不能控制增加功能 ...

  6. 结构型模式-----装饰模式(decorator)

    1.装饰模式 动态的给一个对象添加一些额外的职责,就增加功能来说Decorator模式相比生成子类更为灵活. 要求装饰对象和被装饰对象实现同一个接口,装饰对象持有被装饰对象的实例. 实例一: publ ...

  7. C++结构型模式-装饰模式

    1.1 基本概念 装饰器模式(Decorator Pattern):动态地给一个对象增加一些额外的职责,就增加功能来说,装饰器比生成子类实现更为灵活. 装饰器可以在不改变对象本身的基础上给对象增加额外 ...

  8. 设计模式 — 结构型模式 — 装饰模式

    目录 文章目录 目录 装饰模式 应用场景 代码示例 装饰模式 装饰模式,指的是在不需要改变原类和使用继承的情况下,动态地扩展一个对象的功能.它通过创建一个包装对象,也就是 Python 中的装饰器来包 ...

  9. 设计模式09: Decorator 装饰模式(结构型模式)

    Decorator 装饰模式(结构型模式) 子类复子类,子类何其多 加入我们需要为游戏中开发一种坦克,除了不同型号的坦克外,我们还希望在不同场合中为其增加以下一种多种功能:比如红外线夜视功能,比如水路 ...

最新文章

  1. python同名包_可以使用两个同名的Python包吗?
  2. 选择排序算法流程图_C#实现——十大排序算法之选择排序
  3. 解决Android Studio报错:DefaultAndroidProject : Unsupported major.minor version 52.0
  4. 编程实现算术表达式求值_用魔法打败魔法:C++模板元编程实现的scheme元循环求值器...
  5. 如何选一台好的中低端的笔记本电脑
  6. 浅谈 maxMemory , totalMemory , freeMemory 和 OOM 与 native Heap
  7. 并发编程应用场景_linux网络编程之select函数的并发限制和poll函数应用举例
  8. 实现树状图_举个栗子!Tableau 技巧(132):用参数操作实现数据下钻
  9. 一列数的规则如下: 1、1、2、3、5、8、13、21、34...... 求第30位数是多少?
  10. wow.js中各种特效对应的类名
  11. dev、test和prod是什么意思?
  12. iOS系统下常用的三方应用URL Scheme值
  13. 库克谈人工智能:增长飞快 兼具颠覆性和创造性
  14. 友华改设备标识命令_电信路由器密码怎么修改,路由器牌子是友华通信
  15. 基于IO多路复用的TCP客户端
  16. 打造自己的专属Linux(一):快速建立一个小型Linux
  17. jmeter---Throughput(吞吐量)系列
  18. TFmini Plus 在开源飞控 pixhawk 上的应用
  19. SQL数据库可疑恢复 挂起恢复 置疑恢复 SQL数据库无法附加修复 附加报错 9003
  20. 马克思政治经济学里关于价值的理论

热门文章

  1. 用Zebra做简单的RIP实验
  2. MethodInvoker 委托
  3. Windows各版本GVLK密钥表
  4. ,优视科技发买水货手机利用软件复电通
  5. Python用SSH连接交换机以及多命令输入(paramiko)
  6. 性能测试工具Lighthouse
  7. Android中MediaPlayer播放音乐时自动中断的解决办法
  8. PHP+644是什么,多多自走棋644什么意思
  9. 泛90后男性男装消费偏好报告
  10. c/c++中保留两位有效数字