适配器模式
适配器模式,就是把一个类的接口变换成客户端所能接受的另一个接口,从而使两个接口不匹配的两个类能够在一起工作。
通常用于一个项目需要引用一些开源框架来一起工作的情况下,这些开源框架都有一些关于环境信息的接口,需要从外部传入,但外部接口不一定能匹配,在这种请款下,就需要适配器模式来转换接口。
适配器模式的结构
适配器模式的类结构如图所示:
各角色说明如下:
- Target(目标接口):所需要转换的所期待的接口
- Adaptee(源角色):需要适配的接口
- Adapter(适配器):将原接口适配成目标接口,继承原接口,实现目标接口
I/O中的适配器模式
适配器的作用就是将一个接口适配到另一个接口,在I/O类库有很多这样的类子,如将字符串数据转成字节数据保存到文件中,将字节数据转换成流数据等。下面以InputStreamReader
和OutputStreamWriter
类为例来介绍适配器模式。
InputStreamReader
和OutputStreamWriter
分别继承了Reader和Writer接口,但要创建它们的对象必须在构造函数传入InputStream和OutputStream实例。InputStreamReader
和OutputStreamWriter
的作用也是将InputStream和OutputStream适配到Reader和Writer,InputStreamReader的类结构如图
InputStreamReader实现了Reader接口,并持有了InputStream的引用,这里是通过StreamDecoder类间接持有的,因为从byte到char要经过解码。
很明显适配器就是InputStreamReader类,源角色就是InputStream代表的实例对象,目标接口就是Reader类了。
I/O类库中还有很多类似的用法,如StringReader将String类适配到Reader接口,ByteArrayInputStream适配器将byte数组适配到InputStream流处理接口。
装饰器模式
装饰器模式,顾名思义,就是将某个类重新装扮下,使它在功能上更强大,但是作为原来的这个类,使用者不应该感受到装饰前与装饰后有什么不同,否则就破坏了原有类的结构,所以装饰器模式要做到对装饰类的使用者透明。
装饰器模式的结构
图中各角色描述如下:
- Component:抽象组建角色,定义一组抽象的接口,规定这个被装饰组件都有哪些功能。
- ConcreteComponent:实现这个抽象组件的所有功能;
- Decorator:装饰器角色,它持有一个Component对象实例的引用,定义一个与抽象组件一致的接口;
- ConcreteDecorator:具体的装饰器实践者,负责实现装饰器角色定义的功能。
I/O中的装饰器模式
以FileInputStream为例介绍装饰器模式的使用。
如图所示FileInputStream的类结构图,InputStream类是以抽象组件存在的,而FileInputStream是具体组件,它实现了抽象组件的所有接口,FileInputStream无疑就是装饰角色,它实现了InputStream类的所有接口,并持有InputStream的对象的实例引用;BufferedInputStream是具体的装饰器实现者,它给InputStream附加了功能,这个装饰器类的作用使得InputStream读取的数据保存在内存中,从而提高读取的性能。与这个装饰器类类似的功能还有LineNumberInputStream类,它的作用是提高按行读取数据的功能,它们都让InputStream增强了功能或提升了性能。
适配器模式与装饰器模式的区别
装饰器与适配器模式都有一个别名叫包装模式(Wrapper),它们的作用看似都是起到包装一个类或对象的作用,但是使用它们的目的不一样。适配器模式的意义是将一个接口转变成另一个接口,通过改变接口达到重复使用的目的;而装饰器模式不是要改变被装饰对象的接口,而恰恰要保持原有的接口,但增强原有对象的功能,或者改变原有对象的处理方法而提高性能。所有这两个模式的设计目的是不同的。