定义
- 将一个类的接口转换成客户期望的另一个接口
- 使原本接口不兼容的类可以一起工作
类型
结构型
适用场景
- 已经存在的类,它的方法和需求不匹配时(方法结果相同或相似)
- 不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案
优点
- 能提高类的透明性和复用,现有的类复用但不需要改变
- 目标类和适配器类解耦,提高程序扩展性
- 符合开闭原则
缺点
- 适配器编写过程需要全面考虑,可能会增加系统的复杂度
- 增加系统代码可读的难度
Coding
适配器模式总体来说分三种:默认适配器模式、对象适配器模式、类适配器模式。先不急着分清楚这几个,先看看例子再说。
默认适配器
首先,我们先看看最简单的适配器模式 默认适配器模式(Default Adapter) 是怎么样的。
我们用 Appache commons-io 包中的 FileAlterationListener 做例子,此接口定义了很多的方法,用于对文件或文件夹进行监控,一旦发生了对应的操作,就会触发相应的方法。
public interface FileAlterationListener {
void onStart(final FileAlterationObserver observer);
void onDirectoryCreate(final File directory);
void onDirectoryChange(final File directory);
void onDirectoryDelete(final File directory);
void onFileCreate(final File file);
void onFileChange(final File file);
void onFileDelete(final File file);
void onStop(final FileAlterationObserver observer);
}
此接口的一大问题是抽象方法太多了,如果我们要用这个接口,意味着我们要实现每一个抽象方法,如果我们只是想要监控文件夹中的文件创建和文件删除事件,可是我们还是不得不实现所有的方法,很明显,这不是我们想要的。
所以,我们需要下面的一个适配器,它用于实现上面的接口,但是所有的方法都是空方法,这样,我们就可以转而定义自己的类来继承下面这个类即可。
public class FileAlterationListenerAdaptor implements FileAlterationListener {
public void onStart(final FileAlterationObserver observer) {
}
public void onDirectoryCreate(final File directory) {
}
public void onDirectoryChange(final File directory) {
}
public void onDirectoryDelete(final File directory) {
}
public void onFileCreate(final File file) {
}
public void onFileChange(final File file) {
}
public void onFileDelete(final File file) {
}
public void onStop(final FileAlterationObserver observer) {
}
}
比如我们可以定义以下类,我们仅仅需要实现我们想实现的方法就可以了:
public class FileMonitor extends FileAlterationListenerAdaptor {
public void onFileCreate(final File file) {
// 文件创建
doSomething();
}
public void onFileDelete(final File file) {
// 文件删除
doSomething();
}
}
当然,上面说的只是适配器模式的其中一种,也是最简单的一种,无需多言。下面,再介绍**“正统的”**适配器模式。
类适配器
// 被适配者
public class Adaptee {
public void adapteeRequest(){
System.out.println("被适配者的方法");
}
}
public interface Target {
void request();
}
public class ConcreteTarget implements Target {
public void request() {
System.out.println("ConcreteTarget目标方法");
}
}
public class Adapter extends Adaptee implements Target {
public void request() {
super.adapteeRequest();
}
}
通过继承的方法,适配器自动获得了所需要的大部分方法。这个时候,客户端使用很简单,直接 Target t = new Adapter();
就可以了。
对象适配器
// 被适配者
public class Adaptee {
public void adapteeRequest(){
System.out.println("被适配者的方法");
}
}
public interface Target {
void request();
}
public class ConcreteTarget implements Target {
public void request() {
System.out.println("ConcreteTarget目标方法");
}
}
public class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) { this.adaptee = adaptee; }
public void request() { adaptee.adapteeRequest(); }
}
客户端调用
Adaptee adaptee = new Adaptee();
Target adapter = new Adapter(adaptee);
adapter.request;
一个采用继承,一个采用组合;
类适配属于静态实现,对象适配属于组合的动态实现,对象适配需要多实例化一个对象。
总体来说,对象适配用得比较多。
适配器模式和代理模式的异同
比较这两种模式,其实是比较对象适配器模式和代理模式,在代码结构上,它们很相似,都需要一个具体的实现类的实例。但是它们的目的不一样,代理模式做的是增强原方法的活;适配器做的是适配的活,为的是提供“把鸡包装成鸭,然后当做鸭来使用”,而鸡和鸭它们之间原本没有继承关系。
如果帮到你了,请点击右上角给个赞吧!!
学习笔记。内容总结于Geely老师的《Java设计模式精讲 》和 JavaDoop
欢迎访问我的博客:他和她的猫