结合JDK源码看设计模式——装饰者模式
定义
在不改变原有对象的基础之上,将功能附加到对象上
适用场景
- 扩展一个类的功能
- 动态的给对象增加功能,当功能不需要的时候能够动态删除
详解
在看到定义的时候,可能很多人会想,这不就是继承吗?的确很像,不过是比继承更加有弹性的替代方案。就像原型模式和new之间的关系一样,有区别,但是区别又不是特别大。装饰者一个很重要的词就是动态,他可以灵活的选择要这个功能还是不要。在装饰者中要有四个角色:抽象的实体类,具体的实体类,抽象的装饰者,具体的装饰者。下面画一个大致的UML图
实体类创建之后,如果想扩展实体类那么一般的想法是继承,当然继承也是其中方法之一。上面由UML图就可以看出,在装饰者模式下,我们可以通过装饰类下的扩展功能实现对抽象实体类的包装。当我们需要扩展功能就多加一个扩展功能,不需要扩展功能就不用添加,是一个很动态的扩展方式。下面具体看代码解析。
抽象实体类
public abstract class abstractCake {
protected abstract String getCake();
protected abstract int cost(); }
实体类
public class cake extends abstractCake{
@Override
protected String getCake() {
return "蛋糕";
} @Override
protected int cost() {
return 100;
}
}
抽象装饰类(可以抽象也可以不抽象)
public class AbstractDecorator extends abstractCake {
private abstractCake abstractcake; public AbstractDecorator(abstractCake abstractcake) {
this.abstractcake = abstractcake;
} @Override
protected String getCake() {
return this.abstractcake.getCake();
} @Override
protected int cost() {
return this.abstractcake.cost();
}
}
扩展功能1
public class FruitDecorator extends AbstractDecorator {
public FruitDecorator(abstractCake abstractcake) {
super(abstractcake);
} @Override
protected String getCake() {
return super.getCake()+" 加一层水果";
} @Override
protected int cost() {
return super.cost()+20;
}
}
扩展功能2
public class SugerDecorator extends AbstractDecorator{
public SugerDecorator(abstractCake abstractcake) {
super(abstractcake);
} @Override
protected String getCake() {
return super.getCake()+" 多加糖";
} @Override
protected int cost() {
return super.cost()+10;
}
}
测试类
public class Test {
public static void main(String[] args) { abstractCake ac=new cake();
ac=new FruitDecorator(ac);
ac=new SugerDecorator(ac);
System.out.println(ac.getCake()); }
}
结果
具体的内存图
可以很清楚的看见ac这个抽象类下面一层层包着实体类,解析的时候每一层的包装类的getCake()方法都会送回给抽象实体类,而我的getCake()方法实现的是字符串增加。后面如果我还需要一层水果,那么我就多装饰一次。如果用继承实现,那么我要两层水果,不要糖,那么我就还需要再定义一个实现两层水果的子类,而装饰者模式就只需要修改客户端的ac类实现就行。在JDK中装饰者模式用的最出名的莫过于IO流了,以InputStream为例子。下面是UML图
这就是典型的装饰者。平常我们只需要FileInputStream来读取文件,当我们有一些特殊功能需要,如:BufferedInputStream(完成了缓存功能,使读取文件速度大大提升)和DataInputStream(把byte转换成Java基本数据类型)我们就可以装饰一下InputStream,即灵活又方便。这样使得我们对FileInputStream流的处理更能达到我们想要的预期。当你理解了装饰者模式,我推荐你看这篇博客。这样你就能很好的理解IO流的操作。
总结
装饰者模式是一个比继承更加灵活的扩展方式,要记住装饰者模式必不可少的4个类:抽象的实体类,具体的实体类,抽象的装饰者,具体的装饰者。再结合上面推荐的博客,我相信你不但能理解装饰者,还能更加清晰的理解JDK中的IO流
结合JDK源码看设计模式——装饰者模式的更多相关文章
- 结合JDK源码看设计模式——享元模式
前言 在说享元模式之前,你一定见到过这样的面试题 public class Test { public static void main(String[] args) { Integer a=Inte ...
- 结合JDK源码看设计模式——桥接模式
前言: 在我们还没学习框架之前,肯定都学过JDBC.百度百科对JDBC是这样介绍的[JDBC(Java DataBase Connectivity,java数据库连接)是一种用于执行SQL语句的Jav ...
- 结合JDK源码看设计模式——单例模式
定义: 保证一个类仅有一个实例,并提供一个全局访问点 适用场景: 确保任何情况下这个对象只有一个实例 详解: 私有构造器 单利模式中的线程安全+延时加载 序列化和反序列化安全, 防止反射攻击 结合JD ...
- 结合JDK源码看设计模式——原型模式
定义: 指原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象.不需要知道任何创建的细节,不调用构造函数适用场景: 类初始化的时候消耗较多资源 new产生的对象需要非常繁琐的过程 构造函数比较 ...
- 结合JDK源码看设计模式——简单工厂、工厂方法、抽象工厂
三种工厂模式的详解: 简单工厂模式: 适用场景:工厂类负责创建的对象较少,客户端只关心传入工厂类的参数,对于如何创建对象的逻辑不关心 缺点:如果要新加产品,就需要修改工厂类的判断逻辑,违背软件设计中的 ...
- 结合JDK源码看设计模式——适配器模式
定义: 将一个类的接口转换成客户期望的另外一个接口(重点理解适配的这两个字),使得接口不兼容的类可以一起工作适用场景: 已经存在的类,它的方法和需求不匹配的时候 在软件维护阶段考虑的设计模式 详解 首 ...
- 结合JDK源码看设计模式——模板方法模式
前言: 相信很多人都听过一个问题:把大象关进冰箱门,需要几步? 第一,把冰箱门打开:第二,把大象放进去:第三,把冰箱门关上.我们可以看见,这个问题的答案回答的很有步骤.接下来我们介绍一种设计模式--模 ...
- 结合JDK源码看设计模式——迭代器模式
前言: Iterator翻译过来就是迭代器的意思.在前面的工厂模式中就介绍过了iterator,不过当时介绍的是方法,现在从Iterator接口的设计来看,似乎又是一种设计模式,下面我们就来讲讲迭代器 ...
- 结合JDK源码看设计模式——建造者模式
概念: 将一个复杂对象的构建与它的表示分离.使得同样构建过程可以创建不同表示适用场景: 一个对象有很多属性的情况下 想把复杂的对象创建和使用分离 优点: 封装性好,扩展性好 详解: 工厂模式注重把这个 ...
随机推荐
- spring+springmvc+mybatis构建系统
今天和大家分享的是spring+springmvc+mybatis搭建框架的例子,说到这里不得不说现在市面上一流大公司还有很多用这种架子,创业型公司大部分都用springboot集成的mvc+myba ...
- 0516js综合练习
<!DOCTYPE html><html> <head> <meta charset="UTF-8"> ...
- day12 EL 表达式和国际化开发
day12 EL 表达式和国际化开发 1. EL(Expression Language) 表达式简介 1.1 执行运算 1.2 获取web开发常用对象(el 中定义了11个隐式对象) 1.3 使用 ...
- mysql事务之间的隔离级别
事务间未做隔离,会引起下面这些问题. 1.脏读:一个事务可读到另外一个尚未commit的事务中的数据. 2.不可重复读:在一个事务中,读取同一个数据 a,b,按顺序读取,在读a b 之间,另外一个事 ...
- 前端为什么非要动静分离 说一下CDN托管的意义
大型Web应用对速度的追求并没有止步于仅仅利用浏览器缓存,因为浏览器缓存始终只是为了提升二次访问的速度,对于首次访问的加速,我们需要从网络层面进行优化,最常见的手段就是CDN(Content Deli ...
- java 基础之枚举
问题:对象的某个属性的值不能是任意的,必须为固定的一组取值其中的某一个 解决办法: 1) 在setGrade方法中做判断,不符合格式要求就抛出异常 2) 直接限定用户的选择,通过自定义类模拟枚举的 ...
- Java 保留两位小数填坑
下面直接上代码: DecimalFormat df1 = new DecimalFormat("#.00");DecimalFormat df2 = new DecimalForm ...
- Reading Code Is Hard
注: 以下内容引自: https://blogs.msdn.microsoft.com/ericlippert/2004/06/14/reading-code-is-hard/ Reading Cod ...
- 【译】Flink + Kafka 0.11端到端精确一次处理语义的实现
本文是翻译作品,作者是Piotr Nowojski和Michael Winters.前者是该方案的实现者. 原文地址是https://data-artisans.com/blog/end-to-end ...
- registration_db.go
, atomic.LoadInt64(&p.peerInfo.lastUpdate)) if now.Sub(cur) > inactivityTimeout || p. ...