一、定义

装饰器模式又叫做包装模式(Wrapper)。装饰器模式以对客户端透明的方式扩展对象的功能,是继承关系的一个替代方案。

在以下情况下应该使用装饰器模式:

1.需要扩展一个类的功能,或给一个类增加附加责任

2.需要动态的给一个对象增加功能,这些功能可以再动态的撤销

3.需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使其继承关系变的不现实。

二、类图

装饰器模式中的角色有:

  • 抽象组件角色:给出一个抽象接口,一规范准备接收附加责任的对象
  • 具体组件角色:定义一个将要接收附加责任的类
  • 装饰角色:持有一个组件对象的实例,并定义一个一个与抽象组件接口一致的接口。
  • 具体装饰角色:负责给组件对象"贴上去"附加的责任。

将类图转换为代码,如下所示。

/**
* 装饰者通过对被装饰者进行装饰,从而使得自己拥有的加强的行为
*
* @author lp
*
*/
public class Client { public static void main(String[] args) {
// 被装饰者
Component component = new ConcreteComponent();
// 装饰者
Decorator decorator = new ConcreteDecorator(component); // 被装饰者的行为
component.operation();
// 装饰者既具有被装饰者的行为,也有增加的行为。即对被装饰者进行了装饰。
decorator.operation();
decorator.addedBehavior();
} } /**
* 抽象的被装饰者
*/
interface Component {
void operation();
} /**
* 具体的被装饰者
*/
class ConcreteComponent implements Component{ @Override
public void operation() {
System.out.println("被装饰者的操作");
} } /**
* 抽象的装饰者
*/
interface Decorator extends Component{
/**
* 增加的方法
*/
void addedBehavior();
} /**
* 具体的装饰者
*/
public class ConcreteDecorator implements Decorator { // 持有被装饰者的引用
private Component decoratedComponent; // 通过构造器将被装饰者传进来
public ConcreteDecorator(Component decoratedComponent) {
this.decoratedComponent = decoratedComponent;
} @Override
public void operation() {
System.out.println("decorated operation!");
decoratedComponent.operation();
} /**
* 添加的功能
*/
@Override
public void addedBehavior() {
System.out.println("addedBehaviour!");
} }

应该指出:

  • 装饰类中,有一个私有的属性component,其数据类型是组件(Component)
  • 该装饰器类实现了Component接口
  • 接口的实现方法也值得注意,每一个实现的方法都委派给父类,但并不单纯的委派,而是有功能的增强。

三、JDK中的装饰器模式

JDK中的部分流的实现就使用了装饰器模式,比如BufferedInputStream对InputStream进行了装饰,BufferedReader对Reader进行了装饰,对应的OutputStream和Write也分别被BufferedOutputStream和BufferedWriter装饰了。

下面以BufferedInputStream为例,来分析一下装饰者模式。

/*抽象组件角色*/
public abstract class InputStream implements Closeable {
public abstract int read() throws IOException;
} /*具体组件角色*/
public class FileInputStream extends InputStream{
public int read() throws IOException {
Object traceContext = IoTrace.fileReadBegin(path);
int b = 0;
try {
b = read0();
} finally {
IoTrace.fileReadEnd(traceContext, b == -1 ? 0 : 1);
}
return b;
}
} /*抽象装饰器角色*/
public class FilterInputStream extends InputStream { protected volatile InputStream in; protected FilterInputStream(InputStream in) {
this.in = in;
} public int read() throws IOException {
return in.read();
} public int read(byte b[], int off, int len) throws IOException {
return in.read(b, off, len);
} } /*具体装饰器角色*/
public class BufferedInputStream extends FilterInputStream { protected volatile byte buf[]; public BufferedInputStream(InputStream in){
this(in, defaultBufferSize);
} public synchronized int read() throws IOException {
if (pos >= count) {
fill();
if (pos >= count)
return -1;
}
return getBufIfOpen()[pos++] & 0xff;
} }

BufferedInputStream是继承自FilterInputStream的具体的装饰器类,该类提供一个内存的缓冲区来保存输入流中的数据。这样就带有缓冲功能,提高文件读入的效率。

所以,我们通常以这样的形式来使用它们

BufferedInputStream bis = new BufferedInputStream(new FileInputStream(file));
 ……更多设计模式的内容,可以访问Refactoring.Guru

装饰器模式-Decerator的更多相关文章

  1. PHP 装饰器模式

    装饰器模式:是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能. [装饰器模式中主要角色] 抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这 ...

  2. 设计模式-装饰器模式(Decrator Model)

    文 / vincentzh 原文连接:http://www.cnblogs.com/vincentzh/p/6057666.html 目录 1.概述 2.目的 3.结构组成 4.实现 5.总结 1.概 ...

  3. php设计模式 装饰器模式

    装饰器模式,可以动态地添加修改类的功能. 一个类提供了一项功能,如果要修改并添加额外的功能,传统的编程模式需要写一个子类继承它,并重新实现类的方法.使用装饰器模式,仅需要在运行时添加一个装饰器对象即可 ...

  4. Java设计模式12:装饰器模式

    装饰器模式 装饰器模式又称为包装(Wrapper)模式.装饰器模式以多客户端透明的方式扩展对象的功能,是继承关系的一个替代方案. 装饰器模式的结构 通常给对象添加功能,要么直接修改对象添加相应的功能, ...

  5. 说说设计模式~装饰器模式(Decorator)

    返回目录 装饰器模式,也叫又叫装饰者模式,顾名思义,将一个对象进行包裹,包装,让它变成一个比较满意的对象,这种模式在我们平时项目开发中,经常会用到,事实上,它是处理问题的一种技巧,也很好的扩展了程序, ...

  6. 说说设计模式~装饰器模式(Decorator)~多功能消息组件的实现

    返回目录 为何要设计多功能消息组件 之前写过一篇装饰器模式的文章,感觉不够深入,这次的例子是实现项目中遇到的,所以把它拿出来,再写写,之前也写过消息组件的文章,主要采用了策略模式实现的,即每个项目可以 ...

  7. (十)装饰器模式详解(与IO不解的情缘)

    作者:zuoxiaolong8810(左潇龙),转载请注明出处,特别说明:本博文来自博主原博客,为保证新博客中博文的完整性,特复制到此留存,如需转载请注明新博客地址即可. LZ到目前已经写了九个设计模 ...

  8. 【PHP设计模式 09_ZhuangShiQi.php】装饰器模式 (decorator)

    <?php /** * [装饰器模式 (decorator)] * 有时候发布一篇文章需要经过很多人手,层层处理 */ header("Content-type: text/html; ...

  9. IOS设计模式之二(门面模式,装饰器模式)

    本文原文请见:http://www.raywenderlich.com/46988/ios-design-patterns. 由 @krq_tiger(http://weibo.com/xmuzyq) ...

随机推荐

  1. [CSP-S模拟测试]:幻魔皇(数学)

    题目描述 幻魔皇拉比艾尔很喜欢斐波那契树,他想找到神奇的节点对. 所谓斐波那契树,根是一个白色节点,每个白色节点都有一个黑色节点儿子,而每个黑色节点则有一个白色和一个黑色节点儿子.神奇的节点对则是指白 ...

  2. gsxt滑动验证码

    最后,谈谈滑动验证码. 目前,工商网站已经全面改版,全部采用了滑动验证码,上面绝大多数思路都失效了.对于滑动验证码,网上能搜到的解决方案基本都是下载图片,还原图片,算出滑动距离,然后模拟js来进行拖动 ...

  3. React-Native 之 GD (五)属性声明和属性确认 及 占位图

    1.在 React-Native 创建的自定义组件是可以复用的,而开发过程中一个组件可能会由多个人同时开发或者多个人使用一个组件,为了让开发人员之间减少沟通成本,我们会对某些必要的属性进行属性声明,让 ...

  4. leetcode-mid-Linked list- 116. Populating Next Right Pointers in Each Node

    mycode   93.97% """ # Definition for a Node. class Node(object): def __init__(self, v ...

  5. AtomicBoolean 源码分析

    AtomicBoolean AtomicBoolean 能解决什么问题?什么时候使用 AtomicBoolean? 可原子更新的 boolean 值 1)原子性:在Java中,对基本数据类型变量的读取 ...

  6. Caffe参数交换源码分析

    对境准备:对于多个GPU而言,一台机器2个GPU,参数交换的流程图: 参数交换从main()进入train()函数,在train函数中找到对应源码为: . . . . . ) { caffe::P2P ...

  7. G2 基本使用 折线图 柱状图 饼图 基本配置

    G2的基本使用 1.浏览器引入  <!-- 引入在线资源 --> <script src="https://gw.alipayobjects.com/os/lib/antv ...

  8. js(javascript)取float型小数点后两位数的方法

    以下我们将为大家介绍 JavaScript 保留两位小数的实现方法:四舍五入以下处理结果会四舍五入: ? 1 2 var num =2.446242342; num = num.toFixed(2); ...

  9. 应用安全 - SuiteCRM - 漏洞汇总

    CVE-2019-12598.CVE-2019-12601 SuiteCRM SQL注入与远程代码执行漏洞 SalesAgility SuiteCRM .x版本..x版本和7..5之前的7..x版本中 ...

  10. 简述移动端与PC端的区别

    1.移动端与PC端的区别 PC考虑的是浏览器的兼容性,而移动端开发考虑的更多的是手机兼容性,因为目前不管是android手机还是ios手机,一般浏览器使用的都是webkit内核,所以说做移动端开发,更 ...