1. 装饰者模式的详解
装饰者模式动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性
的替代方案。
装饰者模式设计类之间的关系:
![装饰模式类图1](https://i-blog.csdnimg.cn/blog_migrate/d887f5e03b1c30082b88dd27ca6bdf86.jpeg)
其中Component是一个超类,ConcreteComponen是被装饰者,Decorator是装饰者,装饰者和被装饰者有共同的超类Component,但是此时我们发现Decorator和Component还有另外一条线,这条线表示Decorator还要组合Component。
在我看来装饰的模式中这几个类的主要作用如下:
首先我们看一个这样的现象(这个是我在网上看到的例子,我把它引入进来主要是方便谈谈我的理解)
现象描述:
如果说继承里的超类是一个模具(Component),做出各种各样的稍有不同的子类成品(ConcreteComponen,ConcreteDecoratorA,ConcreteDecoratorB)来满足各种各样的功能。那么把装饰模式比作的一条生产线吧,一个产品(ConcreteComponen)传过来,在各道工序不断地给它加上新的功能,把它一步步按照顺序包装成一个全新的产品(Concrete DecoratorA,Concrete DecoratorB)。记住,这条生产线可能是无限长的,这种包装也可以是无限添加的。
转自:http://xubindehao.iteye.com/blog/474636
1. Component是超类,他出现的意义是什么呢?照理说Decorator直接去组合ConcreteComponent,就可以去加强ConcreteComponent的行为,成而加工出一个不通的子类成品。但是可能有这样一种情况,ConcreteComponent的平级的区域内还有ConcreteComponent1,ConcreteComponent2……这样要为每一个ConcreteComponent都去写一个Decorator吗?这样显然不可能。所以抽象出Component的一个好处就是让ConcreteComponent和Decorator彼此解耦。Decorator只要得到Component对象的引用即可。
2. Decorator是装饰者,而真正装饰的过程是在Decorator的子类ConcreteDecoratorA和ConcreteDecoratorB中完成的,他们使用不同的装饰方法,作出了不同的子类成品。Decorator的作用只是告诉大家,我要去装饰ConcreteComponent,或许还会提供一些用这个装饰者去装饰的而形成的成品共用的特性和功能。
3. 装饰者永远是装饰者,但装饰者装饰出来的成品也有可能会变成被装饰者。即ConcreteDecoratorA和ConcreteDecoratorB有一天也会变到ConcreteComponen的地位。
只不过这个时候在ConcreteDecoratorA的旁边可能会出现一个类似于Decorator的装饰者DecoratorA,它同样要继承并组合超类Component。目的是相同的:解耦,让一个装饰者不必为一个被装饰者而存在
这时候的装饰者模式的结构图变成:
![装饰模式类图2](https://i-blog.csdnimg.cn/blog_migrate/e8602d197ff060e2f21f804ac2d85d00.jpeg)
由上图说明一个道理,如果条件容许的话Decorator和DecoratorA的位置是可以互相交换的。这就像冲一杯带糖的奶粉,Decorator表示放糖,DecoratorA表示放奶粉,其实是先放糖还是先放奶粉,最终都能得到ConcreteDecoratorAA(一杯带糖的奶粉)。当然这是在条件容许的情况下,在有些生产环境中,制做工序(装饰的先后)是不能乱的。
2. 装饰者模式在JAVA IO中的应用
先给出Java IO包中主要类的关系:
java IO包中有四大等级结构InputStream,outputStream, InputStreamReader,outputStreamReader。InputStream和OutputStream处理8位字节流数据, Reader和Writer处理16位的字符流数据。InputStream和Reader处理输入, OutputStream和Writer处理输出。各个体系内部用到的都是装饰者模式,而InputStream和InputStreamReader之间,outputStream和outputStreamReader之间用的是适配器模式
下面主要以InputStream和InputStreamReader为例详解
1. 从装饰者模式看InputStream结构
InputStream的类图关系
class java.lang.Object
|
|—class java.io.InputStream //输入流,字节形式,为以下的基类
| |
| |——ByteArrayInputStream //从字节数组中读取
| |
| |——FileInputStream //从文件中读取数据
| |
| |—— FilterInputStream //过滤流的基类,
| | | // 过滤可以了解为各种处理技术的形象称呼
| | |
| | |——BufferedInputStream //缓冲技术,
| | | // 数据来自底层输入流
| | |
| | |——DataInputStream //可读java数据类型
| | |
| | |——PushbackInputStream //缓冲技术,
| | | // 数据来自任意输入流
| | |
| | |——java.util.zip.GZIPInputStream
| | | //不是java.io包中的流。压缩技术
| | |
| | |——java.security.DigestInputStream
| | | //不是java.io包中的流。处理流的摘要
| | |
| |—— .......
从图中可以看出,InputStream就是装饰者模式中的超类(Component),ByteArrayInputStream,FileInputStream相当于被装饰者(ConcreteComponent),这些类都提供了最基本的字节读取功能。
而另外一个和这两个类是同一级的类FilterInputStream即是装饰者(Decorator),BufferedInputStream,DataInputStream,PushbackInputStream…这些都是被装饰者装饰后形成的成品。
根据装饰者模式的特点,我们可以总结出这些IO流的使用方法:
File file = new File ("hello.txt");
FileInputStream in=new FileInputStream(file);
BufferedInputStream inBuffered=new BufferedInputStream (in);
这里BufferedInputStream主要是提供了缓存机制,先读入一个byte[],等count到达缓存Byte[]的大小的时候,再一次读入。
当然你也可以写成BufferedInputStream inBuffered =
new BufferedInputStream (new FileInputStream(new File ("hello.txt")));
从使用的角度来看装饰者模式,可以看出它的一个缺点:装饰者模式的实现对于使用者是透明的,当使用者不熟悉你的实现的时,就很难理解。
节选自:http://xubindehao.iteye.com/blog/474636