文档章节

装饰者模式-常用设计模式

dapengking
 dapengking
发布于 2014/03/10 00:39
字数 1665
阅读 97
收藏 6
点赞 0
评论 2

装饰者模式的定义:动态的将责任附加到对象上面。若需要扩展功能,装饰者模式提供了比继承更有弹性的替代方案。

如果只是按照上面这样简单的概括,我想应该没有几个人能够看得明白,这装饰者模式究竟是个什么玩意。

不过,我们看到下面这个例子的时候,你也许就会恍然大悟!哦,原来,原来装饰者模式一直就在我们身边,而且,我敢说,你一直都在使用着装饰者模式。

好吧,废话不多说,先上代码:


package decorator;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class Main {
	public static void main(String[] args) {
		int c;
		try {
			//1
			InputStream in  = new BufferedInputStream(new FileInputStream("d:/nodes.cof"));
			//2
			//InputStream in = new FileInputStream("d:/nodes.cof");
			while((c = in.read()) > 0){
				System.out.print((char)c);
			}
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}



上面是一段我们经常能够看到的读取本地文件的java代码。在代码的注释


//1处


//1
			InputStream in  = new BufferedInputStream(new FileInputStream("d:/nodes.cof"));



我们创建了一个文件输入流FileInputStream,然后将FileInputStream类的实例对象作为参数传递给BufferedInputStream对象。从而得到了一个BufferedInputStream对象实例。


接着,在后续的代码中,我们将从文件中读取到的内容输出在终端中。

运行结果,显示这样做是有效的。


但是细心的你可能会发现,在代码中的注释

//2处


//2
			//InputStream in = new FileInputStream("d:/nodes.cof");



有这样一段代码,仅仅只是创建了FileInputStream类的对象实例。当我们用这句代码替换上面的注释//1处的代码之后,运行发现,


运行结果同样是正确的。我们依然能够正确的将文件中的内容显示在终端中。


说到这里,有的朋友可能要问,那既然这种简单的做法,已经满足了功能上的要求,为什么还要多此一举,偏偏要选用复杂的写法呢。毕竟在码代码的过程中,我们能少打一个字是一个字不是么?!^_^

其实,就在刚刚我们已经用到了装饰者模式。。。我们在FileInputStream对象外包装了一个BufferedInputStream对象,从而使得文件读写有了缓存的功能,这样可以减少硬盘的io,提高文件读写的效率~


下面我们来看下精简版的java输入流类之间的UML图。


慢着,这时,我们惊奇的发现:所有的这些类都有一个共同的基类!~因此,所有的这些类的实例,我们都可以认为是InputStream类型的。

在上面的类中,我们将FileInputStream、StringBufferInputStream、ByteArrayInputStream等叫做被装饰类,把FilterInputStream的子类:PushbackInputStream、BufferedInputStream、DataInputStream、LineNumberInputStream等叫做装饰者类。

而且当我们查看jdk的源代码时,会发现


public abstract class InputStream implements Closeable {
InputStream是一个抽象类,它定义了read()接口(抽象方法)



那么,究竟,修饰者是怎么修饰被修饰者的呢?

下面我们来实现一个简化版的装饰者类,LowerCaseInputStream。它的作用是将读取的文件中的字符,全部转化为小写字母。


package decorator;

import java.io.FilterInputStream;
import java.io.IOException;
import java.io.InputStream;

public class LowerCaseInputStream extends FilterInputStream {

	protected LowerCaseInputStream(InputStream in) {
		super(in);
	}

	@Override
	public int read() throws IOException {
		int c = super.read();
		return ( c == -1 ? c : Character.toLowerCase((char)c));
	}
	
}

在这个类中,我们继承了FilterInputStream类,在构造方法中,传入了InputStream类型对象,并传递给父类中的in引用。然后在重写的read方法中,调用super.read(),并对返回的结构进行处理(转换为小写)后,将结果返回。

我们来看看jdk中super.read()的实现:


public int read() throws IOException {
	return in.read();
    }


看明白了吧,调用的super.read()方法,其实,就是调用的in.read()。也就是会调用在创建LowerCaseInputStream类对象是作为构造函数参数,传进的InputStream对象的read方法。

也许看了下面这个图,你会更清楚:in引用的位置,没错,in就是FilterInputStream的成员变量,用来引用,传进来的InputStream类型的对象。

FilterInputStream的结构如下:





类中有一个InputStream类型的引用In。


这时,聪明的你应该已经看出,装饰者模式的奥秘所在了。这会在我们下面这样一条语句中表现的更加明显:


package decorator;

import java.io.BufferedInputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;

public class Main {
	public static void main(String[] args) {
		int c;
		try {
			//1
			InputStream in  = new BufferedInputStream(new FileInputStream("d:/nodes.cof"));
			//2
			//InputStream in = new FileInputStream("d:/nodes.cof");
			//3
			//InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("d:/nodes.cof")));
			while((c = in.read()) > 0){
				System.out.print((char)c);
			}
			
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (IOException e) {
			e.printStackTrace();
		}
	}
}



没错,我们又产生了第三种写法:



InputStream in = new LowerCaseInputStream(new BufferedInputStream(new FileInputStream("d:/nodes.cof")));



在BufferInputStream外层又包裹了一层我们刚刚实现的装饰者对象(LowerCaseInputStream),从而为我们的FileInputStream输入流,增加了转换为小写字母的功能。


可以这么说,装饰者模式的秘密就是在这一层包裹一层的形式中体现出来的。

(当然,你也可以在LowerCaseInputStream外层再包裹无限多个装饰者对象,来扩展更多的功能。)这也就是,我们在本文开头装饰者模式的定义中所说到的“装饰者模式,提供了一种比继承更加灵活的,能够扩展对象功能的方式”

按照我们上面实现的第三中写法的调用方式,实际上,我们最终得到的调用结果可以在下面的图中展示出来:

ok,说到这里,应该是说清楚了。

-----------------------------------------------------------------------------------------------------------

后来自己读了下,我自己应该算是能读明白的,但是,如果一个人之前没有接触过的话,不知道能不能只通过我的这篇博文,弄明白装饰者模式到底是什么东西?

感觉还是自己文笔太差的问题。。。之前在看别人写的书,尤其是翻译过来技术书的时候。总是觉得他们写的内容复杂、不直接,很难懂。有时甚至觉得他们写的都弱爆了。。还不如我自己来写。。可真到了自己来用文字表述的时候,才发现,其实事情并不是之前想象的那么容易的。

嗯,眼高手低不可取啊。。

总之,慢慢练习积累吧,相信文笔会越来越流畅的,描述问题也会越来越清晰起来的~

© 著作权归作者所有

共有 人打赏支持
dapengking
粉丝 7
博文 133
码字总数 53553
作品 0
东城
程序员
加载中

评论(2)

修炼千年的蛇
修炼千年的蛇
很不错,加油
hibegin
hibegin
收了。。
JavaScript常用设计模式

设计模式 设计模式是一种在长时间的经验与错误中总结出来可服用的解决方案。 设计模式主要分为3类: 创建型设计模式:专注于处理对象的创建 Constructor构造器模式,Factory工厂模式,Singl...

a独家记忆
07/13
0
0
JavaScript 中常见设计模式整理

开发中,我们或多或少地接触了设计模式,但是很多时候不知道自己使用了哪种设计模式或者说该使用何种设计模式。本文意在梳理常见设计模式的特点,从而对它们有比较清晰的认知。 JavaScript 中...

牧云云
05/18
0
0
我的Java设计模式-代理模式

写完上一篇之后有小伙伴问我有没有写过代理模式,想看看我的理解。原本我的设计模式系列是按照创建型-行为型-结构型的顺序写下去的,既然小伙伴诚心诚意了,我就大发慈悲的穿插一篇代理模式。...

Jet啟思
2017/11/29
0
0
Java 设计模式(14) —— 复合模式

一、复合模式 模式常一起使用,组合在一个设计解决方案中 复合模式在一个解决方案中结合两个或多个模式,能解决一般性或一系列的问题 二、示例 本次设计模式讲解中无代码示例,由于复合模式是...

磊_lei
05/26
0
0
Android 设计模式-装饰模式(Decorator Pattern)

定义 饰模式指的是在不必改变原类文件和使用继承的情况下,动态地扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象。 UML结构图 Component:组件对象接口 Concre...

Code猎人
05/10
0
0
ES7 Decorator 装饰者模式

原作者:玄农 装饰模式 设计模式大家都有了解,网上有很多系列教程,比如 JS设计模式等等。 这里只分享 装饰者模式 以及在 如何使用 ES7 的 概念 装饰模式 v.s. 适配器模式 装饰模式和适配器...

_朴灵_
05/14
0
0
使用合适的设计模式一步步优化前端代码

作者:晓飞 本文原创,转载请注明作者及出处 --- 在后端语言中,设计模式应用的较为广泛。如Spring中常见的工厂模式、装饰者模式、单例模式、迭代器模式。但是在日常的前端开发中,设计模式使...

iKcamp
2017/10/27
0
0
设计模式之修饰器模式详解(附源代码)

装饰器模式 装饰器模式(Decorator Pattern)允许向一个现有的对象添加新的功能,同时又不改变其结构。这种类型的设计模式属于结构型模式,它是作为现有的类的一个包装。 这种模式创建了一个...

thorhill
03/24
0
0
python 与设计模式 ——工厂与装饰者

python 与设计模式第二篇 添加了test.py,里面的单元测试有使用的方法。 源码地址:[http://git.oschina.net/duoduo3_69/python_design_pattern][1] git checkout v002(这个版本与此篇博客相符...

duoduo3_69
2013/11/27
0
1
Android 装饰者模式初探

前提 最近刚换了一份工作,这段时间一直在熟悉公司的代码逻辑,从中受益颇多。里面的设计模式也挺多的,运用的那个潇洒飘逸,让我好生羡慕。自己对设计模式这块理解的不是特别的深入,能拿出...

Silence潇湘夜雨
07/03
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

AngularJs $resource 高大上的数据交互

$resource 创建一个resource对象的工厂函数,可以让你安全的和RESFUL服务端进行数据交互。 需要注入 ngResource 模块。angular-resource[.min].js 默认情况下,末尾斜杠(可以引起后端服务器...

孟飞阳
9分钟前
0
0
打印斐波那契数

package com.jerry.ch04;public class PrintFibonacci {public static void main(String[] args) {for (int i=0; i<10; i++) {System.out.print(fib(i) + " ");}......

JerryNing
14分钟前
0
0
shell编程

一、shell脚本介绍

人在艹木中
15分钟前
0
0
istio 0.8 遥测 案例

==============遥测===================================== 演示如何从网格中收集遥测信息。 分布式跟踪。如何配置代理以向Zipkin或Jaeger发送跟踪请求 收集度量标准和日志。此任务说明如何配...

xiaomin0322
17分钟前
0
0
ND4J求多元线性回归以及GPU和CPU计算性能对比

上一篇博客《梯度下降法求多元线性回归及Java实现》简单了介绍了梯度下降法,并用Java实现了一个梯度下降法求回归的例子。本篇博客,尝试用dl4j的张量运算库nd4j来实现梯度下降法求多元线性回...

冷血狂魔
18分钟前
0
0
springboot常用注解

@SpringBootApplication: 包含@Configuration、@EnableAutoConfiguration、@ComponentScan 通常用在主类上。 @Service: 用于标注业务层组件。 @RestController: 用于标注控制层组件(如strut...

GoldenVein
24分钟前
1
0
如何进行大数据的入门级学习?

不知道你是计算机专业应届生还是已经从业者。总之,有java基础的学生学习大数据会轻松很多,零基础的小白都需要从java和linux学起。 如果你是一个学习能力特别强,而且自律性也很强的人的话可...

董黎明
38分钟前
0
0
使用Parcelable传递复杂参数

最近做AIDL传递对象,对象必须实现Parcelable的方法才可以被传递。 @Override    public int describeContents() {//这个 默认返回0就行了。        return 0;    }    ...

火云
39分钟前
0
0
十大Intellij IDEA快捷键

Intellij IDEA中有很多快捷键让人爱不释手,stackoverflow上也有一些有趣的讨论。每个人都有自己的最爱,想排出个理想的榜单还真是困难。以前也整理过Intellij的快捷键,这次就按照我日常开发...

HJCui
49分钟前
0
0
word 使用mathtype 编写 数学公式

下载安装,这个链接命名。。。。 http://www.mathtype.cn/xiazai.html 安装之后会多出一个选项 使用内联方式插入图表 编写公式的界面 设置支持latex 语法 输入公式回车就可以看到结果...

阿豪boy
今天
0
0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部