装饰者模式
定义
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
(引用 Head First 设计模式)
一种动态地往一个类中添加新的行为的设计模式。就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。
通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。
(引用 维基百科)
这种类型属于结构型模式,它是作为现有的类的一个包装。创建一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
类图
-
Component
被装饰者抽象类。
-
ConcreteComponent
动态地加上新行为的对象。继承Component。
-
Decorator
装饰者。每个装饰者都有一个组件。持有被装饰者的引用。且需要继承被装饰者。
我们复用继承达到
类型匹配
,而不是复用继承获得了行为
。当我们将装饰者与组件组合时,就是在加入新的行为。所得到的新行为,并不是继承自超类,而是由组合对象得来的。继承Beverage抽象类,是为了有正确的类型,而不是继承它的行为。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。 -
ConcreteDecorator
具体的装饰者。
实现
1. 定义Component抽象类
/**
* 饮料抽象类
* 被装饰者抽象类
*/
public abstract class Beverage {
/**
* 描述字段
*/
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
/**
* 待每个不同类型的子类实现的方法
* @return
*/
public abstract double cost();
}
2. 定义Decorator抽象类
/**
* 装饰者抽象类
* 所有的辅料都要继承该类
* 必须让Condiment Decorator能取代Beverage
*/
public abstract class CondimentDecorator extends Beverage{
/**
* 所有子类必须重新实现该方法。因为装饰器需要保持被装饰者的类方法签名完整
* @return
*/
public abstract String getDescription();
}
3. 定义Component实现类
/**
* 被装饰者实现类
* 浓咖啡
*/
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
@Override
public double cost() {
return 1.99;
}
}
4. 定义Decorator实现类
/**
* 摩卡是一个装饰者,对Beverage进行装饰
* 该类清楚知道被装饰对象。因为需要持有被装饰对象引用
* 1.持有被装饰者的引用
* 2.保证被装饰者的方法签名的实现(getDescription())
* 3.实现装饰(cost)
*/
public class Mocha extends CondimentDecorator{
Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Mocha";
}
@Override
public double cost() {
return .20 + beverage.cost();
}
}
/**
* 1.持有被装饰者的引用
* 2.保证被装饰者的方法签名的实现(getDescription())
* 3.实现装饰(cost)
*/
public class Whip extends CondimentDecorator{
Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
@Override
public String getDescription() {
return beverage.getDescription() + ", Whip";
}
@Override
public double cost() {
return .66 + beverage.cost();
}
}
5. Main方法
public class T {
public static void main(String[] args) {
// 创建基础类
Beverage beverage = new Espresso();
System.out.println(beverage.getDescription() + " $" + beverage.cost());
// 用摩卡装饰
Mocha mocha = new Mocha(beverage);
System.out.println(mocha.getDescription() + " $" + mocha.cost());
// 用Whip装饰Mocha
Whip whip = new Whip(mocha);
System.out.println(whip.getDescription() + " $" + whip.cost());
}
}
Espresso $1.99
Espresso, Mocha $2.19
Espresso, Mocha, Whip $2.8
浅析 Java IO 装饰模式
类图
引用 https://www.cnblogs.com/LUA123/p/10685693.html
-
抽象组件
InputStream
这个抽象类为各种子类型流处理器提供统一的接口。
-
具体组件
由
FileInputStream、ObjectInputStream 、ByteArrayInputStream
等原始流处理器扮演,他们实现了InputStream
的接口,可以被装饰器装饰。 -
抽象装饰类
FilterInputStream
,也实现了InputStream
的接口。 -
具体装饰者
DataInputStream 、BufferedInputStream
。
Java IO流分类
流分类 | 使用分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|---|
抽象基类 | InputStream | OutputStream | Reader | Writer | |
节点流 | 访问文件 | FileInputStream | FileOutStream | FileReader | FileWriter |
节点流 | 访问数值 | ByteArrayInputStream | ByteArrayOutStream | CharArrayReader | CharArrayWriter |
节点流 | 访问管道 | PipedInputStream | PipedOutStream | PipedReader | PipedWriter |
节点流 | 访问字符串 | StringReader | StringWriter | ||
处理流 | 缓冲流 | BufferedInputStream | BufferedOutputStream | BufferedReader | BufferedWriter |
处理流 | 转换流 | InputStreamReader | OutputStreamWriter | ||
处理流 | 对象流 | ObjectInputStream | ObjectOutputStream | ||
处理流 | 抽象基类(过滤) | FilterInputStream | FilterOutputStream | FilterReader | FilterWriter |
处理流 | 打印流 | PrintStream | PrintWriter | ||
处理流 | 推回输入流 | PushbackInputStream | PushbackReader | ||
处理流 | 特殊流 | DataInputStream | DataOutputStream |
节点流和处理流
节点流是真正处理数据的。处理流是装饰者。
-
节点流
- 文件流:
FileInputStream,FileOutputStrean,FileReader,FileWriter
,底层调用native
方法实现文件读取、写入功能。 - 数组流:
ByteArrayInputStream,ByteArrayOutputStream,CharArrayReader,CharArrayWriter
,对数组进行处理的节点流。 - 字符串流:
StringReader,StringWriter
,其中 StringReader 能从 String 中读取数据并保存到 char 数组。 - 管道流:
PipedInputStream,PipedOutputStream,PipedReader,PipedWrite
,对管道进行处理的节点流。
- 文件流:
-
处理流
- 缓冲流 :
BufferedImputStrean,BufferedOutputStream,BufferedReader ,BufferedWriter
,需要父类作为参数构造,增加缓冲功能,避免频繁读写硬盘,可以初始化缓冲数据的大小,由于带了缓冲功能,所以就写数据的时候需要使用 flush 方法,另外,BufferedReader 提供一个 readLine( ) 方法可以读取一行,而 FileInputStream 和 FileReader 只能读取一个字节或者一个字符,因此 BufferedReader 也被称为行读取器。 - 转换流:
InputStreamReader,OutputStreamWriter
,要 inputStream 或 OutputStream 作为参数,实现从字节流到字符流的转换,我们经常在读取键盘输入(System.in)或网络通信的时候,需要使用这两个类。 - 数据流:
DataInputStream,DataOutputStream
,提供将基础数据类型写入到文件中,或者读取出来。
- 缓冲流 :
实例
Reader reader = new FileRead();
小结
-
装饰者和被装饰对象有相同的超类型。所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。我们复用继承达到
类型匹配
,而不是复用继承获得了行为
。 -
你可以用一个或多个装饰者包装一个对象。
-
装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
-
对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
-
局限性
- 导致程序中增加许多功能类似的很小的类
Java 面试宝典是大明哥全力打造的 Java 精品面试题,它是一份靠谱、强大、详细、经典的 Java 后端面试宝典。它不仅仅只是一道道面试题,而是一套完整的 Java 知识体系,一套你 Java 知识点的扫盲贴。
它的内容包括:
- 大厂真题:Java 面试宝典里面的题目都是最近几年的高频的大厂面试真题。
- 原创内容:Java 面试宝典内容全部都是大明哥原创,内容全面且通俗易懂,回答部分可以直接作为面试回答内容。
- 持续更新:一次购买,永久有效。大明哥会持续更新 3+ 年,累计更新 1000+,宝典会不断迭代更新,保证最新、最全面。
- 覆盖全面:本宝典累计更新 1000+,从 Java 入门到 Java 架构的高频面试题,实现 360° 全覆盖。
- 不止面试:内容包含面试题解析、内容详解、知识扩展,它不仅仅只是一份面试题,更是一套完整的 Java 知识体系。
- 宝典详情:https://www.yuque.com/chenssy/sike-java/xvlo920axlp7sf4k
- 宝典总览:https://www.yuque.com/chenssy/sike-java/yogsehzntzgp4ly1
- 宝典进展:https://www.yuque.com/chenssy/sike-java/en9ned7loo47z5aw
目前 Java 面试宝典累计更新 400+ 道,总字数 42w+。大明哥还在持续更新中,下图是大明哥在 2024-12 月份的更新情况:
想了解详情的小伙伴,扫描下面二维码加大明哥微信【daming091】咨询
同时,大明哥也整理一套目前市面最常见的热点面试题。微信搜[大明哥聊 Java]或扫描下方二维码关注大明哥的原创公众号[大明哥聊 Java] ,回复【面试题】 即可免费领取。