设计模式---装饰者模式
首先,从字面意思上看,“装饰”? 可以联想到什么? 对,买房子嘛(吐槽下,房价真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 这个角色也可以是多个的。
装饰者模式的优点就是它的特点:可以在运行时动态,透明的为一个组件扩展功能,比继承更加灵活;缺点也很明显:它会导致设计中出现许多小对象,如果过度使用,会让程序变得很复杂。
设计模式---装饰者模式相关推荐
- Python设计模式-装饰器模式
Python设计模式-装饰器模式 代码基于3.5.2,代码如下; #coding:utf-8 #装饰器模式class Beverage():name = ""price = 0.0 ...
- [Head First设计模式]山西面馆中的设计模式——装饰者模式
原文:[Head First设计模式]山西面馆中的设计模式--装饰者模式 引言 在山西面馆吃鸡蛋面的时候突然想起装饰者这个模式,觉得面馆这个场景跟书中的星巴兹咖啡的场景很像,边吃边思考装饰者模式.这里 ...
- 设计模式——装饰者模式
本文是阅读 Head First 设计模式--装饰者模式的总结. 这本书的教学模式很不错,个人很喜欢,由实际的案例由浅入深,循序渐进的让你明白良好的设计是多么的优雅迷人(回头看看自己的代码,WTF!) ...
- 设计模式装饰者模式_装饰者模式如何拯救了我的一天
设计模式装饰者模式 在工作中,我正在处理庞大的Java代码库,该代码库是由许多不同的开发人员在15年的时间里开发的. 并不是所有的事情都由书来完成,但是同时我通常无法重构遇到的每一个奇怪的事物. 尽管 ...
- 23种设计模式——装饰者模式
文章目录 23种设计模式--装饰者模式 1.装饰者模式概述 2.装饰者模式的结构 3.装饰者模式的实现 4.装饰者模式的应用场景 23种设计模式--装饰者模式 1.装饰者模式概述 背景 有些人为了早上 ...
- 读书笔记---Head First 设计模式--- 装饰者模式
读书笔记-Head First 设计模式- 装饰者模式 装饰者模式(Decorator Pattern) 装饰者模式--动态地将责任附加到对象上.若要扩展功能,装饰者提供了比继承更有弹性的替代方案. ...
- Go 设计模式 - 装饰器模式
装饰模式使用对象组合的方式动态改变或增加对象行为.Go语言借助于匿名组合和非入侵式接口可以很方便实现装饰模式.使用匿名组合,在装饰器中不必显式定义转调原对象方法. 设计模式 装饰器模式 装饰器模式主要 ...
- 10. 设计模式-装饰者模式
文章目录 设计模式-装饰者模式 1. 案例引出装饰者模式 2. 装饰者模式 2.1 装饰者模式定义 2.2 装饰者模式原理 2.3 装饰者模式解决星巴克咖啡订单问题 2.4 代码实现 抽象类Drink ...
- Spring设计模式(装饰器模式)
Spring设计模式(装饰器模式) 模式的定义: 装饰者模式定义: 动态地为一个对象添加一些额外的职责,若要扩展一个对象的功能,装饰者提供了比继承更有弹性的替代方案. 模式的结构图 : 模式包含角 ...
- 设计模式 装饰者模式 带你重回传奇世界
今天继续设计模式之旅,给大家带来装饰者模式,国际惯例,先看定义. 装饰者模式:若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上. 先简单描述下装饰者模式发挥作用的地方,当我 ...
最新文章
- Tarjan算法_LCA
- C++ 虚函数和虚继承解析
- YOLO v3 安装并训练自己数据
- 为节省8亿做迁移,13亿记录出错赔偿29亿
- 天池学习赛:工业蒸汽量预测3——模型训练
- img引用网络图片资源无法加载问题解决
- python用pip安装numpy清华_安装numpy和matplotlib
- MCU_通过windows串口API控制RTS和DTR
- 计算机软考里面的英语试题,2011全国计算机软考网管英语试题及答案(4)
- WordPress主题justnews仿某码屋资源下载站源码-整站打包
- openstack“T版“Placement组件部署
- C#如何新建Excel
- gitblit中忘记admin密码,怎么办?附详细解决方法和截图
- java语言可以编程无人机么_java可以作为第一门编程语言学习吗
- 《Windows IoT 应用开发指南》
- TP-Link WR703N升级64M内存+外接SMA天线+刷OpenWRT(1)硬件介绍
- Gephi简易学习[五]———— 分析红楼梦数据,了解Gephi操作流程
- 如何用三年时间获得十年工作经验?
- Computational Imaging 计算成像(一)
- 怎么样在线Word转换成PDF转换器
热门文章
- 数据库导入Excel表
- 什么是web前端和后端?
- 双链笔记软件评测:Roam Research、 Obsidian、Logseq 思源笔记
- 计算机 法语 考研分数线,2018中国政法大学法语语言文学考研录取名单、招生人数、分数线...
- 剪辑视频,按分秒分割多个视频,并保存片断中的音频
- Python Pygame介绍
- pandorabox php7,矿渣高性价比竞斗云系列八:万能不死PB-boot及安装潘多拉教程
- Lua_windows与linux环境配置(1)
- 最小二乘法与matlab拟合工具箱cftool
- Sans Serif Serif Monospace