首先,从字面意思上看,“装饰”? 可以联想到什么? 对,买房子嘛(吐槽下,房价真tm贵)
有句话说的好,“房子是用来炒的,不是用来住的”。啊呸,错了,说反了。房子买的时候,大部分都是毛坯,或者简装。每个人肯定都想装修一下。对,没错。“装修”的前提,肯定是有了一个房子,它没有满足你的某些需求,然后你在此房子的基础上进行了一些功能添加和扩展。

废话不多说,来了解下“装饰者模式”:
什么是装饰者模式,我就不多说了,网上随便一搜,一大坨,比如:java/android设计模式学习笔记(7):装饰者模式”

举个栗子,暴躁起来(举个栗子):

  • 房子接口
public interface House{void wallColour();void price();
}
  • 普通住房(陈岩石的养老院
public class Yanglaoyuan implements House {public Yanglaoyuan() {System.out.println("这是Yanglaoyuan");}@Overridepublic void wallColour() {System.out.println("Yanglaoyuan——wallColour:白色");}@Overridepublic float price() {System.out.println("Yanglaoyuan——price:10w");return 10000;}
}
  • 祁同伟的别墅
public class BieShu implements House {public BieShu() {System.out.println("这是BieShu");}@Overridepublic void wallColour() {System.out.println("BieShu——wallColour:银色");}@Overridepublic float price() {System.out.println("BieShu——price:380W");return 38000000;}
}
  • 山水庄园会所
public class ShanshuiHotel implements House {public ShanshuiHotel() {System.out.println("这是ShanshuiHotel");}@Overridepublic void wallColour() {System.out.println("ShanshuiHotel——wallColour:金色");}@Overridepublic float price() {System.out.println("ShanshuiHotel——price:3800W");return 380000000;}
}

随着改革开放后人民收入的增加,房子准备装修了:养老院,要贴上壁纸;别墅换高级木质瓷砖;山水庄园要贴一层金箔。

这个时候,这个需求怎么写?

有人说,这还不简单,直接在Yanglaoyuan ,Bieshu,ShanshuiHotel的类里增加个方法就行了呗。
like this:

public class YanglaoyuanNew extends Yanglaoyuan {public YanglaoyuanNew() {super();System.out.println("装修为YanglaoyuanNew");}@Overridepublic void wallColour() {super.wallColour();System.out.println("YanglaoyuanNew装修——wallColour:" + "贴上漂亮的墙纸");}@Overridepublic float price() {System.out.println("YanglaoyuanNew装修——price:300");return super.price() + 300;}public void furniture(){System.out.println("YanglaoyuanNew装修---->>>添加家具");}
}

当然可以,但是要知道这样违反了对扩展开放、对修改关闭的原则(在软件的生命周期内,因为变化、升级和维护等原因需要对软件原有代码进行修改时,可能会给旧代码中引入错误,也可能会使我们不得不对整个功能进行重构,并且需要原有代码经过重新测试)。

解释下为什么一定要遵循对扩展开放、对修改关闭的原则:
就比如上面的栗子,Yanglaoyuan这个类中的方法肯定会在很多地方被调用,如果我们直接修改这个类,有可能引起其他地方出现错误,而这写错误出现的地方是不可预测的。因此在测试的时候,需要对跟此类相关的地方都要进行测试;但是如果我们新建一个类去扩展它的功能,只需要测试跟新建的类相关的即可了。
总的来说遵循一句话:用抽象构建框架,用实现扩展细节

为了不违反 对扩展开放、对修改关闭 的设计原则,首先想到的肯定是对每个实现类继承,子类中扩展功能,增加需求。
like this:

public class YanglaoyuanNew extends Yanglaoyuan {@Overridepublic void wallColour() {System.out.println("Yanglaoyuan——wallColour:白色" + "贴上墙纸");}@Overridepublic float price() {System.out.println("Yanglaoyuan——price:10W + 300");return 100000 + 300;}
}

但是如果,后期再增加需求(比如房子里要增添家居)是不是要再写一个子类?这样会造成子类对象的臃肿。

扩展功能还有一种方法:关联。
使用装饰者模式:
装饰,装饰,肯定需要被装饰者类和装饰者类。

NewHouseWithFurniture 是装饰者类。House 是被装饰者类。装饰者类完全继承实现被装饰者的所有方法,同时还增加扩展新的方法。而且装饰者肯定会执有被装饰着的引用。(这里House是接口,NewHouseWithFurniture 通过多态传入House的子类,从而NewHouseWithFurniture 可以调用子类方法的实现,同时新增方法又可以对所有子类功能进行扩充)
首先对接口进行扩展功能:构建装饰器

public abstract class NewHouseWithFurniture implements House {House house;public NewHouseWithFurniture(House house) {this.house = house;}@Overridepublic void wallColour() {house.wallColour();}@Overridepublic float price() {return house.price();}public void furniture(){System.out.println("---->>>添加家具");}
}

创建新的装修过的养老院

public class NewYanglaoyuan extends NewHouseWithFurniture {public NewYanglaoyuan(House house) {super(house);System.out.println("装修为NewYanglaoyuan");}@Overridepublic void wallColour() {super.wallColour();System.out.println("NewYanglaoyuan装修——wallColour:贴上漂亮的墙纸");}@Overridepublic float price() {System.out.println("NewYanglaoyuan装修——price:300");return super.price() + 300;}@Overridepublic void furniture() {super.furniture();System.out.println("NewYanglaoyuan装修---->>>添加家具");}
}

然后编写测试类:
关注下NewHouseWithFurniture newYanglaoyuan = new NewYanglaoyuan(yanglaoyuan);

public class TestMain {public void start(){System.out.println("-----------------没装修前的:---------------");House yanglaoyuan = new Yanglaoyuan();yanglaoyuan.wallColour();yanglaoyuan.price();System.out.println("-----------------直接在源码上修改的  ---------------");YanglaoyuanNew yanglaoyuan2 = new YanglaoyuanNew();yanglaoyuan2.wallColour();yanglaoyuan2.price();yanglaoyuan2.furniture();System.out.println("-----------------装饰者模式修改的  ---------------");NewHouseWithFurniture newYanglaoyuan = new NewYanglaoyuan(yanglaoyuan);newYanglaoyuan.wallColour();newYanglaoyuan.price();newYanglaoyuan.furniture();}
}

结果

来看下java jdk中源码使用的装饰者设计模式:
InputStream(输入流):是一个抽象类

public abstract class InputStream implements Closeable {// MAX_SKIP_BUFFER_SIZE is used to determine the maximum buffer size to// use when skipping.private static final int MAX_SKIP_BUFFER_SIZE = 2048;...

FileInputStream(文件输入流)InputStream的实现类

public
class FileInputStream extends InputStream
{/* File Descriptor - handle to the open file */private final FileDescriptor fd;/* The path of the referenced file (null if the stream is created with a file descriptor) */private final String path;...

FilterInputStream 输入流的装饰类
实现InputStream的所有方法并且执有InputStream的引用

public
class FilterInputStream extends InputStream {/*** The input stream to be filtered.*/protected volatile InputStream in;/*** Creates a <code>FilterInputStream</code>* by assigning the  argument <code>in</code>* to the field <code>this.in</code> so as* to remember it for later use.** @param   in   the underlying input stream, or <code>null</code> if*          this instance is to be created without an underlying stream.*/protected FilterInputStream(InputStream in) {this.in = in;}...

BufferedInputStream:装饰类的实现类
功能扩展

public
class BufferedInputStream extends FilterInputStream {private static int defaultBufferSize = 8192;.../*** Creates a <code>BufferedInputStream</code>* and saves its  argument, the input stream* <code>in</code>, for later use. An internal* buffer array is created and  stored in <code>buf</code>.** @param   in   the underlying input stream.*/public BufferedInputStream(InputStream in) {this(in, defaultBufferSize);}...
            FileInputStream fiStream = new FileInputStream("C:\\xxxx");BufferedInputStream bufferedInputStream = new BufferedInputStream(fiStream);bufferedInputStream.read();

总结:
继承属于扩展形式之一,但不一定是达到弹性设计的最佳方案;
在程序设计中,应该尽量对修改关闭,对扩展开发,无需修改原有代码;

装饰者可以在被装饰者行为的前后根据实际情况加上自己的行为,必要时也可以将被装饰者行为给替换掉
可以用无数个装饰者包装一个
组件,也就是说,装饰者 A 包装了被装饰者 B ,装饰者 C 再包装装饰者 A,根据实际情况这种行为可以累加到多层,通俗讲就是套上多层外壳;
同时,被装饰者也可以存在多个,也就是说 ConcreteComponent 这个角色也可以是多个的。
装饰者模式的优点就是它的特点:可以在运行时动态,透明的为一个组件扩展功能,比继承更加灵活;缺点也很明显:它会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。

设计模式---装饰者模式相关推荐

  1. Python设计模式-装饰器模式

    Python设计模式-装饰器模式 代码基于3.5.2,代码如下; #coding:utf-8 #装饰器模式class Beverage():name = ""price = 0.0 ...

  2. [Head First设计模式]山西面馆中的设计模式——装饰者模式

    原文:[Head First设计模式]山西面馆中的设计模式--装饰者模式 引言 在山西面馆吃鸡蛋面的时候突然想起装饰者这个模式,觉得面馆这个场景跟书中的星巴兹咖啡的场景很像,边吃边思考装饰者模式.这里 ...

  3. 设计模式——装饰者模式

    本文是阅读 Head First 设计模式--装饰者模式的总结. 这本书的教学模式很不错,个人很喜欢,由实际的案例由浅入深,循序渐进的让你明白良好的设计是多么的优雅迷人(回头看看自己的代码,WTF!) ...

  4. 设计模式装饰者模式_装饰者模式如何拯救了我的一天

    设计模式装饰者模式 在工作中,我正在处理庞大的Java代码库,该代码库是由许多不同的开发人员在15年的时间里开发的. 并不是所有的事情都由书来完成,但是同时我通常无法重构遇到的每一个奇怪的事物. 尽管 ...

  5. 23种设计模式——装饰者模式

    文章目录 23种设计模式--装饰者模式 1.装饰者模式概述 2.装饰者模式的结构 3.装饰者模式的实现 4.装饰者模式的应用场景 23种设计模式--装饰者模式 1.装饰者模式概述 背景 有些人为了早上 ...

  6. 读书笔记---Head First 设计模式--- 装饰者模式

    读书笔记-Head First 设计模式- 装饰者模式 装饰者模式(Decorator Pattern) 装饰者模式--动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. ...

  7. Go 设计模式 - 装饰器模式

    装饰模式使用对象组合的方式动态改变或增加对象行为.Go语言借助于匿名组合和非入侵式接口可以很方便实现装饰模式.使用匿名组合,在装饰器中不必显式定义转调原对象方法. 设计模式 装饰器模式 装饰器模式主要 ...

  8. 10. 设计模式-装饰者模式

    文章目录 设计模式-装饰者模式 1. 案例引出装饰者模式 2. 装饰者模式 2.1 装饰者模式定义 2.2 装饰者模式原理 2.3 装饰者模式解决星巴克咖啡订单问题 2.4 代码实现 抽象类Drink ...

  9. Spring设计模式(装饰器模式)

    Spring设计模式(装饰器模式) 模式的定义: 装饰者模式定义: ​ 动态地为一个对象添加一些额外的职责,若要扩展一个对象的功能,装饰者提供了比继承更有弹性的替代方案. 模式的结构图 : 模式包含角 ...

  10. 设计模式 装饰者模式 带你重回传奇世界

    今天继续设计模式之旅,给大家带来装饰者模式,国际惯例,先看定义. 装饰者模式:若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上. 先简单描述下装饰者模式发挥作用的地方,当我 ...

最新文章

  1. Tarjan算法_LCA
  2. C++ 虚函数和虚继承解析
  3. YOLO v3 安装并训练自己数据
  4. 为节省8亿做迁移,13亿记录出错赔偿29亿
  5. 天池学习赛:工业蒸汽量预测3——模型训练
  6. img引用网络图片资源无法加载问题解决
  7. python用pip安装numpy清华_安装numpy和matplotlib
  8. MCU_通过windows串口API控制RTS和DTR
  9. 计算机软考里面的英语试题,2011全国计算机软考网管英语试题及答案(4)
  10. WordPress主题justnews仿某码屋资源下载站源码-整站打包
  11. openstack“T版“Placement组件部署
  12. C#如何新建Excel
  13. gitblit中忘记admin密码,怎么办?附详细解决方法和截图
  14. java语言可以编程无人机么_java可以作为第一门编程语言学习吗
  15. 《Windows IoT 应用开发指南》
  16. TP-Link WR703N升级64M内存+外接SMA天线+刷OpenWRT(1)硬件介绍
  17. Gephi简易学习[五]———— 分析红楼梦数据,了解Gephi操作流程
  18. 如何用三年时间获得十年工作经验?
  19. Computational Imaging 计算成像(一)
  20. 怎么样在线Word转换成PDF转换器

热门文章

  1. 数据库导入Excel表
  2. 什么是web前端和后端?
  3. 双链笔记软件评测:Roam Research、 Obsidian、Logseq 思源笔记
  4. 计算机 法语 考研分数线,2018中国政法大学法语语言文学考研录取名单、招生人数、分数线...
  5. 剪辑视频,按分秒分割多个视频,并保存片断中的音频
  6. Python Pygame介绍
  7. pandorabox php7,矿渣高性价比竞斗云系列八:万能不死PB-boot及安装潘多拉教程
  8. Lua_windows与linux环境配置(1)
  9. 最小二乘法与matlab拟合工具箱cftool
  10. Sans Serif Serif Monospace