设计模式学习(九):装饰器模式
创始人
2024-04-06 02:47:30
0

设计模式学习(九):装饰器模式

作者:Grey

原文地址:

博客园:设计模式学习(九):装饰器模式

CSDN:设计模式学习(九):装饰器模式

装饰器模式

装饰器模式是一种结构型模式。

顾名思义,就是对某个方法或者对象进行装饰,举个简单的例子,有个圆形类 Circle,我需要把这个圆形的涂上红色,其实就是新增一个装饰器来装饰这个圆形类。

如果要让装饰器通用一些,可以处理圆形类对应的抽象类 Sharp ,那么对于任意 Sharp 的子类,都可以用红色装饰器来涂红色。

示例代码如下

我们先定义 Sharp 这个抽象类

public abstract class Sharp {protected abstract void draw();
}

然后我们定义 Sharp 的装饰类 SharpDecorator ,这个类是所有装饰器类的抽象类,后续的装饰器只需要实现这个抽象类就可以对 Sharp 进行各种装饰了,

public abstract class SharpDecorator extends Sharp {protected Sharp decoratedSharp;public SharpDecorator(Sharp decoratedSharp) {this.decoratedSharp = decoratedSharp;}
}

红色装饰器实现这个抽象类即可:

public class RedSharpDecorator extends SharpDecorator {public RedSharpDecorator(Sharp decoratedSharp) {super(decoratedSharp);}private static void redIt() {System.out.println("[RED]");}@Overrideprotected void draw() {redIt();this.decoratedSharp.draw();redIt();}
}

主方法调用的时候只需要:

new RedSharpDecorator(new Circle()).draw();

UML 图如下:

image

说明:

  1. 装饰器类和原始类继承同样的父类,这样我们可以对原始类“嵌套”多个装饰器类。

  2. 装饰器类是对功能的增强,这也是装饰器模式应用场景的一个重要特点。符合“组合关系”这种代码结构的设计模式有很多,比如代理模式、桥接模式,还有现在的装饰器模式。尽管它们的代码结构很相似,但是每种设计模式的意图是不同的。就拿比较相似的代理模式和装饰器模式来说:

代理模式中,代理类附加的是跟原始类无关的功能;

装饰器模式中,装饰器类附加的是跟原始类相关的增强功能。

装饰器模式应用

在 JDK 中,BufferedInputStream 、 DataInputStream 并非继承自 InputStream ,而是另外一个叫 FilterInputStream 的类。

这是因为 InputStream 是一个抽象类而非接口,而且它的大部分函数(比如 read()available())都有默认实现,按理来说,我们只需要在 BufferedInputStream 类中重新实现那些需要增加缓存功能的函数就可以了,其他函数只需要复用 InputStream 的默认实现。但实际上,这样做是行不通的。对于即便是不需要增加缓存功能的函数来说,BufferedInputStream 还是必须把它重新实现一遍,简单包裹对 InputStream 对象的函数调用。那 BufferedInputStream 类就无法将最终读取数据的任务,委托给传递进来的 InputStream 对象来完成,DataInputStream 也存在跟 BufferedInputStream 同样的问题。为了避免代码重复,Java I/O 包中抽象出了一个装饰器父类 FilterInputStream,包装了 InputStream 的默认实现

package java.io;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[]) throws IOException {return read(b, 0, b.length);}public int read(byte b[], int off, int len) throws IOException {return in.read(b, off, len);}public long skip(long n) throws IOException {return in.skip(n);}public int available() throws IOException {return in.available();}public void close() throws IOException {in.close();}public synchronized void mark(int readlimit) {in.mark(readlimit);}public synchronized void reset() throws IOException {in.reset();}public boolean markSupported() {return in.markSupported();}
}

InputStream 的所有的装饰器类( BufferedInputStream 和 DataInputStream )都继承自这个装饰器父类。这样,装饰器类只需要实现它需要增强的方法就可以了,其他方法继承装饰器父类的默认实现。

其他应用

  • Java 中的 I/O 流, Read/InputStream ,Write/OutputStream

  • Java 中的 UnmodifiableCollection

  • Spring 中的 HttpHeadResponseDecorator, 还有对 Cache 的装饰类 TransactionAwareCacheDecorator

UML 和 代码

UML 图

代码

更多

设计模式学习专栏

参考资料

  • Effective Java中文版(第3版)

  • Head First 设计模式

  • 设计模式-可复用面向对象软件的基础

  • 坦克大战-马士兵

  • 菜鸟教程-设计模式

  • 极客时间-设计模式之美-王争

相关内容

热门资讯

保存时出现了1个错误,导致这篇... 当保存文章时出现错误时,可以通过以下步骤解决问题:查看错误信息:查看错误提示信息可以帮助我们了解具体...
汇川伺服电机位置控制模式参数配... 1. 基本控制参数设置 1)设置位置控制模式   2)绝对值位置线性模...
不能访问光猫的的管理页面 光猫是现代家庭宽带网络的重要组成部分,它可以提供高速稳定的网络连接。但是,有时候我们会遇到不能访问光...
表格中数据未显示 当表格中的数据未显示时,可能是由于以下几个原因导致的:HTML代码问题:检查表格的HTML代码是否正...
本地主机上的图像未显示 问题描述:在本地主机上显示图像时,图像未能正常显示。解决方法:以下是一些可能的解决方法,具体取决于问...
表格列调整大小出现问题 问题描述:表格列调整大小出现问题,无法正常调整列宽。解决方法:检查表格的布局方式是否正确。确保表格使...
不一致的条件格式 要解决不一致的条件格式问题,可以按照以下步骤进行:确定条件格式的规则:首先,需要明确条件格式的规则是...
Android|无法访问或保存... 这个问题可能是由于权限设置不正确导致的。您需要在应用程序清单文件中添加以下代码来请求适当的权限:此外...
【NI Multisim 14...   目录 序言 一、工具栏 🍊1.“标准”工具栏 🍊 2.视图工具...
银河麒麟V10SP1高级服务器... 银河麒麟高级服务器操作系统简介: 银河麒麟高级服务器操作系统V10是针对企业级关键业务...