作者简介:大家好,我是smart哥,前中兴通讯、美团架构师,现某互联网公司CTO
联系qq:184480602,加我进群,大家一起学习,一起进步,一起对抗互联网寒冬
学习必须往深处挖,挖的越深,基础越扎实!
阶段1、深入多线程
阶段2、深入多线程设计模式
阶段3、深入juc源码解析
阶段4、深入jdk其余源码解析
阶段5、深入jvm源码解析
码哥源码部分
码哥讲源码-原理源码篇【2024年最新大厂关于线程池使用的场景题】
码哥讲源码【炸雷啦!炸雷啦!黄光头他终于跑路啦!】
码哥讲源码-【jvm课程前置知识及c/c++调试环境搭建】
码哥讲源码-原理源码篇【揭秘join方法的唤醒本质上决定于jvm的底层析构函数】
码哥源码-原理源码篇【Doug Lea为什么要将成员变量赋值给局部变量后再操作?】
码哥讲源码【你水不是你的错,但是你胡说八道就是你不对了!】
码哥讲源码【谁再说Spring不支持多线程事务,你给我抽他!】
终结B站没人能讲清楚红黑树的历史,不服等你来踢馆!
打脸系列【020-3小时讲解MESI协议和volatile之间的关系,那些将x86下的验证结果当作最终结果的水货们请闭嘴】
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
(引用 Head First 设计模式)
一种动态地往一个类中添加新的行为的设计模式。就功能而言,修饰模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。
通过使用修饰模式,可以在运行时扩充一个类的功能。原理是:增加一个修饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。修饰类必须和原来的类有相同的接口。
(引用 维基百科)
这种类型属于结构型模式,它是作为现有的类的一个包装。创建一个装饰类,用来包装原有的类,并在保持类方法签名完整性的前提下,提供了额外的功能。
Component
被装饰者抽象类。
ConcreteComponent
动态地加上新行为的对象。继承Component。
Decorator
装饰者。每个装饰者都有一个组件。持有被装饰者的引用。且需要继承被装饰者。
我们复用继承达到类型匹配
,而不是复用继承获得了行为
。当我们将装饰者与组件组合时,就是在加入新的行为。所得到的新行为,并不是继承自超类,而是由组合对象得来的。继承Beverage抽象类,是为了有正确的类型,而不是继承它的行为。行为来自装饰者和基础组件,或与其他装饰者之间的组合关系。
ConcreteDecorator
具体的装饰者。
/**
* 饮料抽象类
* 被装饰者抽象类
*/
public abstract class Beverage {
/**
* 描述字段
*/
String description = "Unknown Beverage";
public String getDescription() {
return description;
}
/**
* 待每个不同类型的子类实现的方法
* @return
*/
public abstract double cost();
}
/**
* 装饰者抽象类
* 所有的辅料都要继承该类
* 必须让Condiment Decorator能取代Beverage
*/
public abstract class CondimentDecorator extends Beverage{
/**
* 所有子类必须重新实现该方法。因为装饰器需要保持被装饰者的类方法签名完整
* @return
*/
public abstract String getDescription();
}
/**
* 被装饰者实现类
* 浓咖啡
*/
public class Espresso extends Beverage {
public Espresso() {
description = "Espresso";
}
@Override
public double cost() {
return 1.99;
}
}
/**
* 摩卡是一个装饰者,对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();
}
}
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
抽象组件InputStream
这个抽象类为各种子类型流处理器提供统一的接口。
具体组件
由FileInputStream、ObjectInputStream 、ByteArrayInputStream
等原始流处理器扮演,他们实现了InputStream
的接口,可以被装饰器装饰。
抽象装饰类
FilterInputStream
,也实现了InputStream
的接口。
具体装饰者
DataInputStream 、BufferedInputStream
。
流分类 | 使用分类 | 字节输入流 | 字节输出流 | 字符输入流 | 字符输出流 |
---|---|---|---|---|---|
抽象基类 | 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();
装饰者和被装饰对象有相同的超类型。所以在任何需要原始对象(被包装的)的场合,可以用装饰过的对象代替它。我们复用继承达到类型匹配
,而不是复用继承获得了行为
。
你可以用一个或多个装饰者包装一个对象。
装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的。
对象可以在任何时候被装饰,所以可以在运行时动态地、不限量地用你喜欢的装饰者来装饰对象。
局限性