文章目录

  • 类图
  • 适配器模式入门小demo
    • 重构第三登录自由适配的业务场景
      • 简单的写法:
      • 优雅的写法
    • 适配器的3种方式
    • 适配器模式的本质
    • 什么时候使用适配器模式
    • 相关模式

类图

适配器模式的应用场景:
适配器模式(Adapter Pattern)是指将一个类的接口转换成客户期望的另一个接口,使原本的接口不兼容的类可以一起工作,属于结构型设计模式。
适配器适用于以下几种业务场景:

  • 1、已经存在的类,它的方法和需求不匹配(方法结果相同或相似)的情况。
  • 2、适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案。有点亡羊补牢的感觉。
    生活中也非常的应用场景,例如电源插转换头、手机充电转换头、显示器转接头。

适配器模式入门小demo


适配的接口

public interface DC5 {int outputDC5V();
}

被适配的接口/类

public class AC220 {public int outputAC220V() {int output = 220;System.out.println("输出交流电: " + output + "v");return output;}}

适配类:

public class PowerAdapter implements DC5 {private AC220 ac220;public PowerAdapter(AC220 ac220) {this.ac220 = ac220;}@Overridepublic int outputDC5V() {int adapterInput = ac220.outputAC220V();int adapetOutput = adapterInput / 44;System.out.println("使用PowerAdapter 输入AC: " + adapetOutput + "V " + "输出DC:" + adapetOutput + "V");return adapetOutput;}
}

测试

public class OjectAdapterTest {public static void main(String[] args) {DC5 dc5 = new PowerAdapter(new AC220());dc5.outputDC5V();}
}

重构第三登录自由适配的业务场景

下面我们来一个实际的业务场景,利用适配模式来解决实际问题。年纪稍微大一点的小伙伴一定经历过这样一个过程。我们很早以前开发的老系统应该都有登录接口,但是随着业务的发展和社会的进步,单纯地依赖用户名密码登录显然不能满足用户需求了。现在,我们大部分系统都已经支持多种登录方式,如QQ 登录、微信登录、手机登录、微博登录等等,同时保留用户名密码的登录方式。虽然登录形式丰富了,但是登录后的处理逻辑可以不必改,同样是将登录状态保存到session,遵循开闭原则。

简单的写法:

/*** Title: ResultMsg* Description: 统一返回格式** @author hfl* @version V1.0* @date 2020-05-21*/
public class ResultMsg {private int code;private String msg;private Object data;public ResultMsg(int code, String msg, Object data) {this.code = code;this.msg = msg;this.data = data;}public int getCode() {return code;}public void setCode(int code) {this.code = code;}public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}public Object getData() {return data;}public void setData(Object data) {this.data = data;}
}

登录参数:

public class Member {private String username;private String password;private String mid;private String info;public String getUsername() {return username;}public void setUsername(String username) {this.username = username;}public String getPassword() {return password;}public void setPassword(String password) {this.password = password;}public String getMid() {return mid;}public void setMid(String mid) {this.mid = mid;}public String getInfo() {return info;}public void setInfo(String info) {this.info = info;}
}
/*** 最简单的 注册登录方式(被适配类Adaptee)*/
public class SiginService {/*** 注册方法** @param username* @param password* @return*/public ResultMsg regist(String username, String password) {return new ResultMsg(200, "注册成功", new Member());}/*** 登录的方法** @param username* @param password* @return*/public ResultMsg login(String username, String password) {return null;}
}
/*** 新增第三方登录方式, * 兼容原来的注册登录(通过继承方式实现)*/
public class SinginForThirdService extends SiginService {public ResultMsg loginForQQ(String openId){//1、openId是全局唯一,我们可以把它当做是一个用户名(加长)//2、密码默认为QQ_EMPTY//3、注册(在原有系统里面创建一个用户)//4、调用原来的登录方法return loginForRegist(openId,null);}public ResultMsg loginForWechat(String openId){return null;}public ResultMsg loginForToken(String token){//通过token拿到用户信息,然后再重新登陆了一次return  null;}public ResultMsg loginForTelphone(String telphone,String code){return null;}public ResultMsg loginForRegist(String username,String password){super.regist(username,null);return super.login(username,null);}
}

测试: 原来的用户名和密码登录 和现在新增的 通过qq和微信的方式都可以使用到。

public class SiginForThirdServiceTest {public static void main(String[] args) {SinginForThirdService service = new SinginForThirdService();service.login("tom","123456");service.loginForQQ("sdfasdfasf");service.loginForWechat("sdfasfsa");}
}

优雅的写法

上面的写法可以满足适配,但是,spring源码中采用更优雅的方式,我们也可以模仿下spring源码的方式,反射生成适配类 来实现这个需求:


public class PassportForThirdAdapter extends SiginService implements IPassportForThird {@Overridepublic ResultMsg loginForQQ(String id) {return processLogin(id, LoginForQQAdapter.class);}@Overridepublic ResultMsg loginForWechat(String id) {return processLogin(id, LoginForWechatAdapter.class);}@Overridepublic ResultMsg loginForToken(String token) {return processLogin(token, LoginForTokenAdapter.class);}@Overridepublic ResultMsg loginForTelphone(String telphone, String code) {return processLogin(telphone, LoginForTelAdapter.class);}@Overridepublic ResultMsg loginForRegist(String username, String passport) {super.regist(username, null);return super.login(username, null);}//这里用到了简单工厂模式及策略模式private ResultMsg processLogin(String key, Class<? extends LoginAdapter> clazz) {try {LoginAdapter adapter = clazz.newInstance();if (adapter.support(adapter)) {System.out.println("传入参数是: key"+"; 调用 "+adapter+" 的login方法");return adapter.login(key, adapter);} else {return null;}} catch (Exception e) {e.printStackTrace();}return null;}
}
/*** Title: IPassportForThird* Description: 第三方登录兼容接口** @author hfl* @version V1.0* @date 2020-05-23*/
public interface IPassportForThird {/*** QQ 登录* @param id* @return*/ResultMsg loginForQQ(String id);/*** 微信登录* @param id* @return*/ResultMsg loginForWechat(String id);/*** 记住登录状态后自动登录* @param token* @return*/ResultMsg loginForToken(String token);/*** 手机号登录* @param telphone* @param code* @return*/ResultMsg loginForTelphone(String telphone, String code);/*** 注册后自动登录* @param username* @param passport* @return*/ResultMsg loginForRegist(String username, String passport);
}
public interface LoginAdapter {boolean support(Object adapter);ResultMsg login(String id, Object adapter);
}
public class LoginForQQAdapter implements LoginAdapter{@Overridepublic boolean support(Object adapter) {return adapter instanceof LoginForQQAdapter;}@Overridepublic ResultMsg login(String id, Object adapter) {return null;}
}
/*** 新浪微博登录*/
public class LoginForSinaAdapter implements LoginAdapter {@Overridepublic boolean support(Object adapter) {return adapter instanceof LoginForSinaAdapter;}@Overridepublic ResultMsg login(String id, Object adapter) {return null;}
}
public class LoginForTelAdapter implements LoginAdapter {@Overridepublic boolean support(Object adapter) {return  adapter instanceof LoginForTelAdapter;}@Overridepublic ResultMsg login(String id, Object adapter) {return null;}
}
/*** Title: LoginForTokenAdapter* Description: token自动登录** @author hfl* @version V1.0* @date 2020-05-23*/
public class LoginForTokenAdapter implements LoginAdapter{@Overridepublic boolean support(Object adapter) {return adapter instanceof LoginForTokenAdapter;}@Overridepublic ResultMsg login(String id, Object adapter) {return null;}
}
/*** Title: LoginForWechatAdapter* Description: 微信登录** @author hfl* @version V1.0* @date 2020-05-23*/
public class LoginForWechatAdapter  implements LoginAdapter{@Overridepublic boolean support(Object adapter) {return adapter instanceof LoginForWechatAdapter;}@Overridepublic ResultMsg login(String id, Object adapter) {return null;}
}
public class PassportTest {public static void main(String[] args) {IPassportForThird passportForThird = new PassportForThirdAdapter();//原来的接口 可用passportForThird.loginForRegist("admin","admin");//新增适配的接口 同样可用passportForThird.loginForQQ("11");}
}

至此,我们在遵循开闭原则的前提下,完整地实现了一个兼容多平台登录的业务场景。
当然,我目前的这个设计也并不完美,仅供参考,感兴趣的小伙伴可以继续完善这段代
码。例如适配器中的参数目前是写死为String,改为Object[]应该更合理。

适配器的3种方式

1.类适配器
2.对象适配器器
3.接口适配器
之前的一篇适配的文章有提到。

适配器模式的本质

什么时候使用适配器模式

相关模式



个人微信公众号:
搜索: 怒放de每一天
不定时推送相关文章,期待和大家一起成长!!


适配器模式实战场景和本质相关推荐

  1. 【初学疑惑】开发者工具可信度高吗?Python爬虫实战场景

    本篇博客是一个小小的 Python 爬虫实践,重点为解释在 Python 爬虫实战过程中,浏览器的开发者工具和代码抓取的网页源码,存在数据差异. 翻译一下就是开发者工具和爬虫采集到的源码,不一样. 本 ...

  2. Android实战场景 - 限制EditText仅支持输入数字、英文、汉字,禁止输入表情等特殊符号

    因项目需求,需要禁止用户输入表情符号,具体如下 ~ EditText相关Blog TextView.EditText属性大全 监听 EditText 文本变化 设置 EditText 光标颜色与下划线 ...

  3. Android实战场景 - 输入手机号、银行卡号、身份证号时动态格式化

    在日常项目开发中,如果稍微严谨点的话,其中关于手机号.银行卡号.身份证号的输入格式有做了限制格式化操作,主要是为了给用户带来更好的体验感: 最近同事正好问到了我这个问题,虽然以前做过这类型功能,但是并 ...

  4. Android实战场景 - 保存WebView中的图片到相册

    去年同事写了一个 "在H5中保存图片到相册" 的功能,虽然有大致实现思路,实现起来也没问题,但是感觉同事考虑问题的很周全,当时候就想着去学习一下,但是项目太赶没顾得上,索性现在有时 ...

  5. 软件测试用例_软件测试用例设计实战场景法

    不点蓝字,我们哪来故事? 目录 场景法 扩展例子 场景法介绍 影子 场景法用例设计举例 场景法设计用例步骤和表示 场景法举例 总结 场景法的注意点 场景法 影子 本来想直接跳过场景法的,今天群友提出问 ...

  6. ocx控件 postmessage消息会消失_通过HackerOne漏洞报告学习PostMessage漏洞实战场景中的利用与绕过...

    0x00 前言 这是一篇关于postMessage漏洞分析的文章,主要通过hackerone平台披露的Bug Bounty报告,学习和分析postMessage漏洞如何在真实的场景中得到利用的. 0x ...

  7. CountDownLatch、CyclicBarrier实战场景分析(附代码)

    目录 概述 CountDownLatch概述 CountDownLatch实战之前置任务处理 CountDownLatch实战之后置任务处理 CountDownLatch实战之最优接口逻辑 Cycli ...

  8. 23种设计模式——工厂模式+适配器模式实战

    一.简介 业务需求,需要对不同的浏览器返回不同的url地址. 例如: Chrom浏览器返回:'http://www.chrom.com', IE浏览器返回:'http://www.ie.com' 二. ...

  9. 越狱动画之python 实战场景解密篇三完结篇

    今天的越狱动画有些复杂, 希望可以清晰的呈现给大家.不清楚的后期还会做代码和知识点添加和内容优化!updates: 已更新部分代码! 第七关: 场景:填满能量屏障,爬上能量电梯, 接近创造之结. 需求 ...

最新文章

  1. BFS之三(单向bfs和康托压缩)
  2. php unpack linux,PHP unpack()函数中断处理信息泄露漏洞
  3. c语言知识点演讲,C语言实验复习资料讲课讲稿.doc
  4. 分享ASP.NET+jQuery MiniUI后台购物管理
  5. Apache 配置 Basic 认证
  6. 记录Docker in Docker 安装(CentOS7)
  7. pat 乙级 1018 锤子剪刀布(C++)
  8. vim快捷键使用记录
  9. pyqt5示例_木辛老师的编程课堂:Python和Qt第一讲之初识PyQt5
  10. Android 实现静默安装
  11. Python 基础—— collections 模块
  12. python安装mysql模块_Python:使用pip安装MySQL-python模块
  13. Jbpm工作流表补数记录
  14. 将xml文件由格式化变为压缩字符串
  15. 电脑网速,别把宽带浪费了,一招提升电脑网速
  16. stm32 国产QMC5883L 进口HMC5883 三轴电子指南针加速度传感器
  17. 4.JavaScript对象和初始面向对象
  18. special effects - 星空宇宙背景特效
  19. Kibana7.9.2设置elasticsearch索引过期时间,到期自动删除
  20. java 打印菱形和空心菱形

热门文章

  1. Cutting(思维)
  2. SpringCLoud+redis+es高并发项目《四》
  3. Java:通过读取文件头来得到文件真实类型
  4. 2022-2028全球与中国质地食品成分市场现状及未来发展趋势
  5. 读源码(四)—— js Promise
  6. UED设计流程及方法
  7. GIC Partitioning
  8. 苹果Iphone/Ipad--L2TP虚拟教程
  9. Linux下挂载NTFS分区
  10. 内部稽核与内部控制管理体系关系的探讨