Java设计模式 -10- 装饰器模式(Decorator模式)

  • 前言
  • 装饰器模式的定义与特点
    • 优点:
    • 缺点:
  • 装饰器模式的结构与实现
    • 1. 模式的结构
    • 2. 模式的实现
  • 装饰器模式的应用实例
  • 装饰器模式的应用场景
  • 装饰器模式的扩展

前言


结构型模式描述如何将类或对象按某种布局组成更大的结构。它分为类结构型模式和对象结构型模式,前者采用继承机制来组织接口和类,后者釆用组合或聚合来组合对象。

由于组合关系或聚合关系比继承关系耦合度低,满足“合成复用原则”,所以对象结构型模式比类结构型模式具有更大的灵活性。

结构型模式分为以下 7 种:

  1. 代理(Proxy)模式:为某对象提供一种代理以控制对该对象的访问。即客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些特性。
  2. 适配器(Adapter)模式:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
  3. 桥接(Bridge)模式:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现的,从而降低了抽象和实现这两个可变维度的耦合度。
  4. 装饰(Decorator)模式:动态地给对象增加一些职责,即增加其额外的功能。
  5. 外观(Facade)模式:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问。
  6. 享元(Flyweight)模式:运用共享技术来有效地支持大量细粒度对象的复用。
  7. 组合(Composite)模式:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性。

以上 7种结构型模式,除了适配器模式分为类结构型模式和对象结构型模式两种,其他的全部属于对象结构型模式,下面我们会分别、详细地介绍它们的特点、结构与应用。


上班族大多都有睡懒觉的习惯,每天早上上班时间都很紧张,于是很多人为了多睡一会,就会用方便的方式解决早餐问题。有些人早餐可能会吃煎饼,煎饼中可以加鸡蛋,也可以加香肠,但是不管怎么“加码”,都还是一个煎饼。在现实生活中,常常需要对现有产品增加新的功能或美化其外观,如房子装修、相片加相框等,都是装饰器模式。

在软件开发过程中,有时想用一些现存的组件。这些组件可能只是完成了一些核心功能。但在不改变其结构的情况下,可以动态地扩展其功能。所有这些都可以釆用装饰器模式来实现。

装饰器模式的定义与特点

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

优点:

  • 装饰器是继承的有力补充,比继承灵活,在不改变原有对象的情况下,动态的给一个对象扩展功能,即插即用。
  • 通过使用不用装饰类及这些装饰类的排列组合,可以实现不同效果。
  • 装饰器模式完全遵守开闭原则。

缺点:

  • 装饰器模式会增加许多子类,过度使用会增加程序得复杂性。

装饰器模式的结构与实现

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

1. 模式的结构

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

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

装饰器模式的结构图如下图所示:

2. 模式的实现

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

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() 方法来显示,下图所示是其结构图。

程序代码如下:

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");}
}

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

装饰器模式的应用场景

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

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

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

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

BufferedReader in = new BufferedReader(new FileReader("filename.txt"));
String s = in.readLine();

装饰器模式的扩展

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

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

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

Java设计模式 -10- 装饰器模式(Decorator模式)相关推荐

  1. Java单体应用 - 架构模式 - 03.设计模式-10.装饰器模式

    原文地址:http://www.work100.net/training/monolithic-architecture-design-patterns-decorator-pattern.html ...

  2. java设计模式之 装饰器模式

    装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构. 这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装. 这种模式创建了一个装 ...

  3. (设计模式七)java设计模式之装饰器模式

    一.简介: 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构.这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装.这种模式创建了一个装饰类 ...

  4. java设计模式之装饰器模式

    一.装饰器模式简介 装饰器模式可以动态给一个对象添加一些额外的职责,同时又不改变其结构.就象在墙上刷油漆.使用Decorator模式相比用生成子类方式达到功能的扩充显得更为灵活.这种模式创建了一个装饰 ...

  5. Java 设计模式之装饰器模式

    装饰器模式用于给原有对象增加新功能的场景, 拿食物冰淇淋,香草巧克力作为例子,给冰淇淋加香草,或者加巧克力,或者加香草和巧克力. 首先定义一个食物接口: /*** 装饰类和被装饰类共同继承的抽象类* ...

  6. java设计模式之装饰器模式(包装器模式)

    显然设计模式往往追求开闭原则,所以往往是面向接口编程,那么万事万物就是先写接口,把需求弄出来,这里以一辆车子在陆地上跑为基础,对它进行装饰,使它可以具备更多的"功能",达到装饰的效 ...

  7. 初学Java常用设计模式之——装饰器模式

    声明:转载请附上原文链接 提示:标题序号从8开始,是照应不同设计模式笔记发布的顺序而定的,比如,上一篇文章 初学Java常用设计模式之--桥接模式和组合模式 序号从7开始. 8. 装饰器设计模式(重点 ...

  8. python中的装饰器、装饰器模式_python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

  9. python 设计模式之装饰器模式 Decorator Pattern

    #写在前面 已经有一个礼拜多没写博客了,因为沉醉在了<妙味>这部小说里,里面讲的是一个厨师苏秒的故事.现实中大部分人不会有她的天分.我喜欢她的性格:总是想着去解决问题,好像从来没有怨天尤人 ...

  10. 设计模式学习----装饰器模式

    这两天本来是自在学习java collection Framework的Fail Fast底层机制,看到核心的部分时,突然意识到设计模式的问题,上大学到现在我还没有真正理解过设计模式的概念,于是用了大 ...

最新文章

  1. http和dubbo的区别_(转载)Dubbo 接口是什么? 与http 接口有什么区别
  2. 听障人士的“有声桥梁”:百度智能云曦灵-AI手语平台发布
  3. 在.NET上如何根据字符串动态创建控件
  4. python django项目断点调试
  5. 数据结构碎碎念(一)
  6. solaris11-text-安装GUI(gnome)
  7. 7-130 古风排版 (20 分)
  8. 技术对游戏公司来讲到底有多重要?
  9. 人工智能综述性论文_人工智能论文研读:深度学习算法与架构综述(包含详细统计表)...
  10. Struts标签 bean:write用法
  11. Web前端工程师知识脉络图
  12. 微信公众平台开发(九) 数据库操作
  13. python生成word文档有哪些库_python实现生成word文档并转为pdf
  14. Python Pandas实现简单Excel数据表合并
  15. 运维简历怎么写项目描述_简历中的项目描述
  16. 关于PaaS平台开发的五个大坑
  17. 用excel做数据分析必知的编程语言
  18. 卑鄙与高尚,理想与现实
  19. 独立站卖家如何利用Google广告引流
  20. 大数据架构中的流式架构和Kappa架构

热门文章

  1. PHP一句话木马实验
  2. RabbitMQ高级特性——死信队列DLX以及代码测试
  3. Bootstrap 教程第三课:制作有图标的按钮
  4. Understanding of LFP and EEG
  5. vue引入外部js和css
  6. 外汇骗局有哪些?如何挽回损失?
  7. 超神学院基因计算机,《超神学院》超级基因的起源
  8. python箱线图_从零开始学Python-matplotlib系列(III):箱线图
  9. Mmseg分词算法及实现
  10. 一文带你入门UML!