写点什么

百度工程师教你玩转设计模式(适配器模式)

作者:百度Geek说
  • 2022-10-26
    上海
  • 本文字数:2648 字

    阅读完需:约 9 分钟


作者 | 北极星小组


在现实生活中,经常会遇到两个“对象” 因为接口不兼容而不能一起工作的场景,这时需要第三者进行适配,如:国内的充电线插头不一定适用国外的插座需要借助转接头、SD 卡无法直接链接电脑需要借助读卡器、用直流电的笔记本电脑接交流电源时需要一个电源适配器等。


在软件设计中,需要开发的具有某种业务功能的组件在现有的组件库中已经存在,但它们与当前系统的接口规范不兼容,如果重新开发这些组件成本又很高,这时用适配器模式能很好地解决这些问题。


适配器模式(Adapter Pattern):是指将某个类的接口转化成客户端期望的另一个接口,主要目的是兼容性,让原本因接口不匹配不能工作的两个类可以协同工作。



△适配器示意图


适配器模式包含如下角色:


  • Target:目标抽象类, 定义客户要使用的接口

  • Adapter:适配器类,将 Adaptee 的接口进行适配转换

  • Adaptee:适配者类,需要被转换接口的对象

  • Client:客户类,通过适配器接口 Target 去使用 Adaptee 的功能



△对象适配器



△类适配器

一、适配器模式在文档业务场景中的应用(对象适配器)

微软 office 文档有两种数据格式,即 office2007(OOXML 格式)和 Office2003(二进制格式)。在新业务场景中,因现有系统已经具备 Office2007 文档处理功能组件(数据、阅读器等),现在需要在此基础上扩充支持 office2003 格式的文档。即复用现有的 office2007 组件类,但接口与复用环境要求不一致,此时可以使用适配器模式。


示例使用对象适配器方式,忽略业务处理细节,仅做流程上的抽象来表明适配器模式的使用,根据模式结构抽象出各个角色类:


  • Doc2003 目标抽象类

  • Doc2007 适配者类

  • DocAdapter 适配器类

  • Document 客户类


// Document客户类使用方public class Document {  public void View(Doc2003 doc) {    doc.show()  }}
// Doc2003接口抽象public interface IDoc2003 { void show();}
// Doc2007适配者类public class Doc2007 { public void show() { System.out.println("office2007标准处理流程"); }}
// DocAdapter适配器类public class DocAdapter implements IDoc2003 { private Doc2007 doc2007; public DocAdapter(Doc2007 doc2007){ this.doc2007 = doc2007; } @Override public void show() { System.out.println("适配器:这里省略了适配到2007的一堆适配逻辑..."); doc2007.show(); }}
// 测试类public class Test { public static void main(String[] args) { Document document = new Document(); Doc2003 doc2003 = new DocAdapter(new Doc2007()) ; document.view(doc2003); }}
复制代码

二、适配器模式在替换依赖组件场景中的应用(类适配器)

在实际的研发过程中,我们经常会需要对依赖组件进行更新迭代。在替换时,相关调用代码,往往分布在非常多的地方,并且由于调用方法与参数不一致,逐个修改工作量大,且存在遗漏风险,这时候可以使用类适配器,将接口统一,减少相关代码的改动。


示例使用类适配器方式,忽略业务处理细节,仅做流程上的抽象来表明适配器模式的使用,根据模式结构抽象出各个角色类:


  • AHandler 目标抽象类

  • BHandler 适配者类

  • BAdapter 适配器类

  • Client 客户类


//原依赖库-目标抽象类public class AHandler {    public void operation() {}}
//新依赖库-适配者类public class BHandler { public void action() {}}
//适配器类public class BAdapter extends BHandler { public void operation() { ... super.action(); ... }}
//客户类public class Client { public static void main(String[] args) { //原调用 AHandler aHandler = new AHandler(); aHandler.operation(); //新调用 BAdapter bAdapter = new BAdapter(); bAdapter.operation(); }}
复制代码

三、适配器模式在接口实现场景的应用(接口适配器)

在实际的开发过程中,一个接口有大量的方法,但是对应的不同类只需要关注部分方法,其他无关的方法全都实现过于繁琐,尤其是涉及的实现类过多的情况。


例如,现有一个需要的目标接口对象 Target,定义了大量相关的方法。但是在实际使用过程只需分别关注其中部分方法,而不是全部实现。在此场景中:


被依赖的目标对象:TargetObj


适配器:Adapter


客户端:Client


// 目标对象:定义了大量的相关方法public interface TargetObj {    void operation1();    void operation2();    void operation3();    void operation4();    void operation5();}
// 适配器:将目标接口定义的方法全部做默认实现public abstract class Adapter implements TargetObj { void operation1(){} void operation2(){} void operation3(){} void operation4(){} void operation5(){}}
// 客户端:采用匿名内部类的方式实现需要的接口即可完成适配public class Client {
public static void main(String[] args) { Adapter adapter1 = new Adapter() { @Override public void operation3() { // 仅仅实现需要关注的方法即可 System.out.println("operation3") } } Adapter adapter2 = new Adapter() { @Override public void operation5() { // 仅仅实现需要关注的方法即可 System.out.println("operation5") } } adapter1.operation3(); adapter2.operation5();
}
}
复制代码

四、总结

以上介绍了三种使用适配器模式的场景,适配器模式本质上是将现有的不兼容的接口转换为需要的接口,不需要改变原来的代码结构即可实现新的功能,通常实现方式上有:


  1. 对象适配器:通过对象的组合来达到适配目的;

  2. 类适配器:通过类的继承或者接口的实现来达到适配目的;

  3. 接口适配器:通过实现接口的方式转换来达到适配的目的;


适配器模式是在现有的类和系统都不易修改的情况下使用,在系统设计之初慎用适配器模式,这样会导致代码可读性变差,不易维护。


---------- END ----------


推荐阅读【技术加油站】系列:


揭秘百度智能测试在测试评估领域实践


百度工程师带你探秘C++内存管理(理论篇)


从零到一了解APP速度测评


百度工程师教你玩转设计模式(工厂模式)


揭秘百度智能测试在测试分析领域实践


百度用户产品流批一体的实时数仓实践



发布于: 2022-10-26阅读数: 30
用户头像

百度Geek说

关注

百度官方技术账号 2021-01-22 加入

关注我们,带你了解更多百度技术干货。

评论

发布
暂无评论
百度工程师教你玩转设计模式(适配器模式)_Java_百度Geek说_InfoQ写作社区