adapter design pattern
适配模式的概念、适配模式的结构、适配模式的优缺点、适配模式的使用场景、适配模式的实现示例(类适配模式和对象适配模式)、适配模式的源码分析
1、适配模式的概念
适配器模式,即将一个类的某个接口转换成用户希望的另一个接口,使得原本由于接口不兼容而不能在一起工作的类可以在一起工作。适配器模式分为类适配器模式和对象适配器模式,类适配器模式依赖继承关系实现,故比依赖组合或聚合关系实现的对象适配器模式耦合度高。
2、适配模式的结构
- 抽象原有接口:即用户最终要访问的接口,定义原有接口的行为。
- 具体原有接口:实现抽象原有接口,实现原有接口的具体行为。
- 抽象目标接口:即用户要求的接口,定义用户目标接口的行为。
- 适配器:实现抽象目标接口,实现目标接口的行为。
3、适配模式的优缺点
- 优点:
- 用户可以透明的调用目标接口(这里的目标接口指原有接口)。
- 复用了现有的组件,即无需修改已有的组件即可实现用户对目标接口的调用。
- 缺点:
- 对适配器来说,更换适配器较复杂。
- 在类适配模式中,依赖继承关系实现,且目标类必须抽象。
4、适配模式的使用场景
- 系统需要使用现有的类,但现有类的接口不符合系统的需要。
- 想建立一个可以重复使用的类,用于一些彼此之间没有太大关联的类。
- 通过接口转换,将一个类嵌入到另一个类中。
5、适配模式的实现示例
5.1、类适配模式的实现示例
抽象原有接口:
public interface Original {
/**
* 定义原有类行为
* @param name
*/
void behavior(String name);
}
具体原有接口:
public class SpecificOriginal implements Original {
@Override
public void behavior(String name) {
System.out.println("我是具体原有对象 " + name);
}
}
抽象目标接口:
public interface Target {
/**
* 定义目标类行为
*/
void behavior();
}
适配器:
public class Adapter extends SpecificOriginal implements Target {
@Override
public void behavior() {
System.out.println("我是适配器对象");
this.behavior("momo");
}
}
测试:
public class ClassAdapterTest {
public static void main(String[] args) {
Target adapter = new Adapter();
adapter.behavior();
}
}
测试结果:
我是适配器对象
我是具体原有对象 momo
5.2、对象适配模式的实现示例
抽象原有接口:
public interface Original {
/**
* 定义原有类行为
* @param name
*/
void behavior(String name);
}
具体原有接口:
public class SpecificOriginal implements Original {
@Override
public void behavior(String name) {
System.out.println("我是具体原有对象 " + name);
}
}
抽象目标接口:
public interface Target {
/**
* 定义目标类行为
*/
void behavior();
}
适配器:
public class Adapter implements Target {
private Original original;
public Adapter(Original original) {
this.original = original;
}
@Override
public void behavior() {
System.out.println("我是适配器对象");
this.original.behavior("momo");
}
}
测试:
public class ObjectAdapterTest {
public static void main(String[] args) {
Target adapter = new Adapter(new SpecificOriginal());
adapter.behavior();
}
}
测试结果:
我是适配器对象
我是具体原有对象 momo
6、适配模式的源码分析
jdk 中的 Reader(字符流)、InputStream(字节流)的适配使用的是 InputStreamReader。InputStreamReader 继承自 java.io 包中的 Reader,实现了其抽象未实现的方法,如下:
public class InputStreamReader extends Reader {
private final StreamDecoder sd;
/**
* Reads a single character.
*
* @return The character read, or -1 if the end of the stream has been
* reached
*
* @exception IOException If an I/O error occurs
*/
public int read() throws IOException {
return sd.read();
}
/**
* Reads characters into a portion of an array.
*
* @param cbuf Destination buffer
* @param offset Offset at which to start storing characters
* @param length Maximum number of characters to read
*
* @return The number of characters read, or -1 if the end of the
* stream has been reached
*
* @exception IOException If an I/O error occurs
* @exception IndexOutOfBoundsException {@inheritDoc}
*/
public int read(char cbuf[], int offset, int length) throws IOException {
return sd.read(cbuf, offset, length);
}
...
}
public class StreamDecoder extends Reader {
...
}
从源码可以看出,InputStreamReader 是对同样实现了 Reader 的 StreamReader 的 的封装,所以从表面看是 InputStreamReader 做了 InputStream 字节流到 Reader 字符流的转换,实际上其是调用了 StreamDecoder 的实现。