有过多年开发经验的开发人员都有这样的经验。不管之前的用户调研、需求分析等工作做的多么的完美。系统的需求变更总是不断变化的。所谓"智者千虑必有一失,愚者千虑必有一得"。不管多么聪明的人,经过多少次的思考,总有考虑不周全的时候。何况想我这样的平凡之人呢。既然,软件开发“必然”的变更总会出现,那么在我们开发的时候,当出现一些变更时,是否有一种补救的模式能够快速的扩展原有的系统,而不必将项目推到重来呢?今天我们就讲一讲适配器模式。

一、业务场景
任何软件系统的开发少不了人员信息模块。2017年我在一个某个国企内做项目。国企的人员1万多号人。项目中就有一个模块关于公司人员信息的获取。模块也非常的简单。在结合了调研,了解了用户的需求后。做了一个简单的设计,大概如下(已简化代码)。

很简单,有一个对象UserInfo存储了用户的所有信息,实际的系统当然有很多的子类。这个UserInfo在系统的很多地方使用,你可以查看自己的信息,当然也可以修改。先看接口:

public interface UserInfo {//获取用户姓名public String getUserName();//获取用户年龄public String getUserAge();//获取用户手机public String getUserPhone();//获取用户家庭住址public String getUserHomeAdress();//.....
}

员工的接口有了,我们设计了一个实现类实现了它…

public class UserInfoService implements UserInfo {@Overridepublic String getUserName() {// 业务逻辑  ...return "获取用户姓名...";}@Overridepublic String getUserAge() {// 业务逻辑  ...return "获取用户年龄...";}@Overridepublic String getUserPhone() {// 业务逻辑  ...return "获取用户手机号...";}@Overridepublic String getUserHomeAdress() {// 业务逻辑  ...return "获取用户家庭住址...";}
}

整个项目上线后,都能平稳的运行,当然中间反反复复修修补补也是正常的事情,总的来说在项目一期,应用都还不错。隔了一年,可能是我们公司做的项目还不错,这家国企又将项目的二期交给了我们公司(也许是我们是乙方,还经常996的原因)。二期项目当然需求的模块更多。其中有一个功能就是将该国企独立的集团下用户的信息同步过来。

独立集团的用户信息接口和这个信息的接口不一样,它把人员的信息分为了两个部分,基本信息和详细信息,并且都放在了HashMap结构中,当然这也是一个可以接受的模式,我们看一下接口定义:

public interface OutSystemUser {//获取用户基本信息public Map getUserBaseInfo();//获取用户外部信息public Map getUserDetailInfo();
}

独立集团的人员信息接口是这样实现的:

public class OutSystemUserService implements OutSystemUser {@Overridepublic Map getUserBaseInfo() {HashMap map = new HashMap();map.put("userName", "外部用户名:...");map.put("userAge", "外部用户年龄:...");return map;}@Overridepublic Map getUserDetailInfo() {HashMap map = new HashMap();map.put("homeAddress", "外部用户家庭地址:...");map.put("otherInfo", "外部用户其他信息:...");return map;}
}

看到这里,我们先不管接口的设计好坏,问题是我们的系统需要和这个系统交互。到底该怎么办?我们不可能为了这一个功能把我们运行稳定的系统进行大改动。所以怎么办呢,我们可以转化,先拿到对方的数据对象,然后转化成我们自己的数据对象就可以了。中间加一层转换器。

按照这样的思路,我们可以简单的画一下类图:


型。OutUserInfoAdapter可以说是一个两面派。至于怎么样在在本系统中使用外部系统的对象,很简单,RMI就可以实现,类似有远程过程调用。只要有接口,就可以把远程对象当成本地的对象调用。大家有时间自己可以研究。我们先看看这个中转类的代码实现:

public class OutUserInfoAdapter extends OutSystemUserService implements UserInfo {private Map userBaseInfo = super.getUserBaseInfo();private Map userDetailInfo = super.getUserDetailInfo();@Overridepublic String getUserName() {String userName = (String) userBaseInfo.get("userName");return userName;}@Overridepublic String getUserAge() {String userAge = (String) userBaseInfo.get("userAge");return userAge;}@Overridepublic String getUserPhone() {String userPhone = (String) userBaseInfo.get("userPhone");return userPhone;}@Overridepublic String getUserHomeAdress() {String homeAddress = (String) userDetailInfo.get("homeAddress");return homeAddress;}
}

看到没有,使用这样的一个转化,就可以轻松的实现系统的用户信息同步。我们可以看看使用的场景,获取本系统的用户信息:

 UserInfo userInfoService=new UserInfoService();for(int i =0;i<10;i++){System.out.println(userInfoService.getUserName());}

使用外部系统的用户信息:

  UserInfo outUserInfo=new OutUserInfoAdapter();for(int i =0;i<10;i++){System.out.println(outUserInfo.getUserName());}

可以看到,在使用了以上的模式后,只修改了一句话,其他的业务逻辑都不用修改就可以解决了系统对接的问题。只是添加了这样的一个类,尽少量的修改。这就是适配器模式。

二、适配器模式定义
适配器模式(Adapter Pattern) : 将一个类的接口变成客户端所期待的接口,从而使得原本接口不匹配而无法在一起工作的两个类能够在一起工作。适配器模式又叫包装模式。

其实在生活中,经常使用到这样的思想,比如手机的充电口电压都非常的低,不能够直接使用220伏特的交流电,为此每一个手机的充电器都自带了一个变压转化器。是的手机能够正常的充电使用。

适配器模式中有三个角色:

Target目标角色:

该角色定义了我要把其他的类转换成这样的接口,就是我们希望需要的接口。上文所说的UserInfo接口,我们需要这样的接口,才能不改变现有的系统。

Adaptee源角色:

这个是已经存在的角色,他是一个运行良好的类或对象。就像上文的OutSystemUserService,是一个外部的类。我们想把源角色经过适配器改成目标角色

Adapter适配器角色:

  这个是该模式的核心,其他两个角色都是已经存在的,而这个适配器角色是我们新建的,职责也是非常的简  单:把源角色转换成目标角色。上文中提到的:OutUserInfoAdapter

以上就是适配器的原理,但是适配器模式远远没有这么简单。

三、对象适配器模式
以上我们将适配器角色继承了源角色,即OutUserInfoAdapter继承OutSystemUserService,从而拥有了获取用户基本信息和详情信息的方法,有了这两个方法才能实现用户信息的转换。

试想一下,如果外部系统的用户信息放在了两个不同的接口中,就是说,用户的基本信息在一个接口,详情信息在一个接口,总共有两个接口,两个实现类,我们的OutUserInfoAdapter不可能继承两个类,这是行不通的。该怎么办呢,其实很简单我们可以让OutUserInfoAdapter拥有这两个接口的实现类,通过类关联的方法实现。这种方法我们称之为对象适配器模式。之前说的都是类适配器模式。我们先看类图:

                                  ## 对象适配器模式类图

通过以上的修改。同样也可以以少量的代码变动,完成相应的功能,实现系统的对接。

四、小结
适配器模式可以说是一个补偿模式,一般来说都是解决接口不相容的问题的。因为系统的设计不可能百分百的完美。需求的变更才是永恒的主题。既然无法逃避这个问题,我们就需要这样的一个模式去应对它。试想,在系统开发时,需求巨变、业务飞速而导致你极度郁闷,极度的崩溃时,适配器模式通过对其他接口的转换,包装成我们可以使用的接口对象,从而简化了系统大规模变更导致的风险,是不是非常的试用呢?

设计模式之适配器模式 :外部系统接口的使用相关推荐

  1. 外部系统接口稽核经验谈

    新业务流程系统上线接入到集团云门户系统.按设计要求通过了单点登录和待办/待阅任务推送功能. 但是,在接口稽核时,云门户运维人员天天反馈稽核问题,虽然这些不影响单点登录和待办任务处理功能,但是涉及到用户 ...

  2. [学习笔记]设计模式[6]-{适配器模式外观模式}

    设计原则 最少知识原则:只和你的密友谈话 这个原则的意思是,在系统设计的过程中,不要让太多的类耦合在一起,免得对系统一部分的修改会影响到其他部分.在设计系统之前,应该首先注意对象与对象之间的交互关系, ...

  3. sap与外部系统的接口怎么实现

    根据系统数据交换的方式以及读写数据的相对关系不同,可以将外部系统与SAP系统的接口形式分为:主动式,被动式和中间式1.主动式接口即外部系统将SAP系统所需的信息直接写入SAP系统的数据库中.这种方式要 ...

  4. 商品库存推送至外部系统API接口文档

    没有与外部系统对接,商品库存数据不通?往下看看 电商API文档---点击查看!http://ds.xnxxxk.cn/apijk?comefrom=CSDN&plan=kucuntongbu1 ...

  5. Java怎么保证数据一致性_连续调用多个外部系统写接口保证数据一致性的思路...

    概述 某些场景下,我们将业务数据落地之前,是需要先调用外部系统的多个写接口,当这些写接口都操作成功了,我们才将业务数据落地到自己本地的数据库里面.比如说: public void updateProd ...

  6. SAP 调用外部系统webservice接口(SOAP-XML)-SOAMANAGER

    SAP 调用外部系统webservice接口(SOAP-XML)-SOAMANAGER 文章目录 SAP 调用外部系统webservice接口(SOAP-XML)-SOAMANAGER 一.GUI客户 ...

  7. C#设计模式(7)——适配器模式(Adapter Pattern)

    一.引言 在实际的开发过程中,由于应用环境的变化(例如使用语言的变化),我们需要的实现在新的环境中没有现存对象可以满足,但是其他环境却存在这样现存的对象.那么如果将"将现存的对象" ...

  8. 【设计模式】适配器模式 ( 概念 | 适用场景 | 优缺点 | 外观模式对比 | 适配器模式相关角色 | 类适配器 | 对象适配器 | 实现流程 )

    文章目录 I . 适配器模式概念 II . 适配器模式 适用场景 III . 适配器模式 优缺点 IV . 适配器模式 与 外观模式对比 V . 适配器模式 相关角色 ( 重点 ) VI . 适配器模 ...

  9. 设计模式 之 适配器模式

    目的 将一个类的接口转换为另一个符合客户期望的接口 达到的目的: 种类 有两种: 对象适配器 [ ] 类适配器(嗷--暂时没有实际场景让自己完全明白嗷?) NOTE: 对象适配器和类适配器使用两种不同 ...

最新文章

  1. 【直播】林锦弘:CV赛事高分经验分享
  2. 近年推荐系统论文调查汇总
  3. 三星笔记本又发新品,这一次仍然惊艳
  4. 为什么美团打车、滴滴外卖必败?君智谢伟山揭秘了背后的竞争战略逻辑
  5. PMP 考的人多了?就没有含金量了?
  6. 【英语学习】【WOTD】newspeak 释义/词源/示例
  7. 【SpringCloud】服务注册之 Consul
  8. 我的IT之路2011(二)
  9. redhat linux 中用锐捷客服端实现上网
  10. 前端使用jspdf生成PDF通过ajax传输后台生成PDF文件
  11. web网站加速之CDN技术原理
  12. Effective Java 2.0_中英文对照_Item 7
  13. git删除远程创库命令
  14. python plc fx5u_三菱FX5U可编程控制器硬件及指令篇
  15. opencv-python将两个文件夹下的照片拼接一起,然后保存
  16. Go1.19 那些事:国产芯片、内存模型等新特性,你知道多少?
  17. jQuery - 基于serializeArray的serializeObject
  18. python的docx库使用教程
  19. 编译原理——SysY编译器实践报告
  20. Vue Baidu Map组件: 点、线、多边形、圆形、撤销、返回

热门文章

  1. 音视频从入门到精通——ffmpeg3之打印多媒体文件音视频信息
  2. 北京清华大学英文地址
  3. 【iCore2双核心板视频教程三】iM_LAN 100M 以太网模块TCP压力测试(更新视频教程)...
  4. 基于FPGA的多路抢答器设计程序代码与测试代码
  5. java算法:随机生成英文单词表快速查询含有和不含有的单词(不考虑大小写)
  6. 拼多多2019秋招内推笔试-业务平台开发
  7. 我走过山的时候山不说话
  8. mysql租房house查询_多条件查询(php+mysql) 租房子例子
  9. CMD以及运行命令整理
  10. 洛咕 P3964 [TJOI2013]松鼠聚会