博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
装饰者模式-常用设计模式
阅读量:6247 次
发布时间:2019-06-22

本文共 4338 字,大约阅读时间需要 14 分钟。

hot3.png

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

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

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

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

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,说到这里,应该是说清楚了。

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

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

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

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

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

转载于:https://my.oschina.net/dapengking/blog/206705

你可能感兴趣的文章
用正则表达式匹配网址URL中最后一个反斜杠/后面的内容
查看>>
Define custom @Required-style annotation in Spring
查看>>
General: Know How to Use InetAddress
查看>>
php 克隆和引用类
查看>>
Linux编程之变量
查看>>
weblogic的下载安装及myeclipse的配置
查看>>
android 第一次运行应用的引导界面
查看>>
我的vimrc配置
查看>>
Java运行原理及内存分析
查看>>
构建之法阅读笔记03
查看>>
C#进程监控
查看>>
Vijos1404 遭遇战 最短路,dijkstra,堆
查看>>
svn解决与优化帮助
查看>>
SQL update select结合语句详解及应用
查看>>
[转]阿里要走102年,阿里的工程师能走多远呢?
查看>>
《算法导论》读书笔记之第15章 动态规划—最长公共子序列
查看>>
从$a_n=f(n)$的角度理解数列中的表达式$a_{n+1}=\frac{k}{a_n}$
查看>>
Redis以及Redis的php扩展安装无错版
查看>>
总结性博客作业
查看>>
Windows Phone 8初学者开发—第11部分:设置SounBoard应用程序
查看>>