是指将一个类的接口转换为用户期望的另一个接口,使原本接口不兼容的类可以一起工作。
适用场景:
1、已经存在的类的方法和需求不匹配(方法结果相同或类似)的情况。
2、适配器模式不是软件初始阶段考虑的设计模式,是随着软件的发展,由于不同产品、不同厂家
造成功能类似而接口不同的问题的解决方案。
3、生活中类似的场景比如电源插座转换头、手机充电转换头、显示器转换头、电压转换等。
注:
博客:
霸道流氓气质的博客_CSDN博客-C#,架构之路,SpringBoot领域博主
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。
民用电220V交流电,但手机使用5V直流电,因此给手机充电时需要使用电源适配器进行转换。
创建AC220类,表示220V交流电
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- //220V交流电
- public class AC220 {
- public int outputAC220V(){
- int output = 220;
- System.out.println("输出交流电:"+output+"V");
- return output;
- }
- }
创建DC5接口,表示5V直流电
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- //5V直流电
- public interface DC5 {
- int outputDC5V();
- }
创建电源适配器类PowerAdapter
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- public class PowerAdapter implements DC5{
-
- private AC220 ac220;
- public PowerAdapter(AC220 ac220){
- this.ac220 = ac220;
- }
- @Override
- public int outputDC5V() {
- int adapterInput = ac220.outputAC220V();
- //变压器
- int adapterOutput = adapterInput/44;
- System.out.println("使用PowerAdapter输入AC:"+adapterInput+"V,输出DC:"+adapterOutput+"V");
- return adapterOutput;
- }
- }
客户端测试代码
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- public class PowerAdapterTest {
- public static void main(String[] args) {
- DC5 dc5 = new PowerAdapter(new AC220());
- dc5.outputDC5V();
- }
- }
系统初始只有登录接口,随着业务发展,需要新增第三方登录比如QQ登录和微信登录。
登录后台的处理逻辑不改,同样将登录状态保存到session。
创建统一的返回结果类ResultMsg
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- /**
- * 返回结果类
- */
- 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;
- }
- }
老系统的登录代码如下
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- 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;
- }
- }
为遵循开闭原则,不修改老系统的代码,开始重构代码。
创建Member类
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- 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;
- }
- }
再创建一个新的类继承原来的代码
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- public class SignForThirdService extends SiginService{
-
- //qq登录
- public ResultMsg loginForQQ(String openId){
- //1、openId是全局唯一的,我们可以把它当成一个加长用户名
- //2、自动生成默认密码
- //3、注册-在原系统在创建一个用户
- //4、调用原来的登录方法
- return loginForRegist(openId,null);
- }
-
- //微信登录
- public ResultMsg loginForWechat(String openId){
- return null;
- }
-
- public ResultMsg loginForRegist(String username,String password){
- super.regist(username,null);
- return super.login(username,null);
- }
- }
客户端测试代码
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- public class SignForThirdServiceTest {
- public static void main(String[] args) {
- SignForThirdService signForThirdService = new SignForThirdService();
- //不改变原来的代码,也能兼容新的需求,还可以再加一层策略模式
- signForThirdService.loginForQQ("badaodechengxvyuan");
- }
- }
通过如上即可实现代码的兼容。
但是代码还可以再优化,不同的登录方式创建不同的Adapter
首先创建LoginAdapter接口
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- public interface LoginAdapter {
- boolean support(Object adapter);
- ResultMsg login(String id,Object adapter);
- }
然后,分别实现不同的登录方式,QQ登录LoginForQQAdapter
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- public class LoginForQQAdapter implements LoginAdapter{
- @Override
- public boolean support(Object adapter) {
- return adapter instanceof LoginForQQAdapter;
- }
-
- @Override
- public ResultMsg login(String id, Object adapter) {
- return null;
- }
- }
微信登录LoginForWechatAdapter
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- public class LoginForWechatAdapter implements LoginAdapter{
- @Override
- public boolean support(Object adapter) {
- return adapter instanceof LoginForWechatAdapter;
- }
-
- @Override
- public ResultMsg login(String id, Object adapter) {
- return null;
- }
- }
然后创建第三方登录兼容接口IPassportForThrid
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- public interface IPassportForThird {
- /**
- * QQ登录
- * @param id
- * @return
- */
- ResultMsg loginForQQ(String id);
-
- /**
- * 微信登录
- * @param id
- * @return
- */
- ResultMsg loginForWechat(String id);
- }
实现兼容PassportForThirdAdapter
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- /**
- * 第三方登录自由适配
- */
- public class PassportForThirdAdapter extends SiginService implements IPassportForThird{
- @Override
- public ResultMsg loginForQQ(String id) {
- return processLogin(id,LoginForQQAdapter.class);
- }
-
- @Override
- public ResultMsg loginForWechat(String id) {
- return processLogin(id,LoginForWechatAdapter.class);
- }
-
- //这里用到了简单工厂模式和策略模式
- private ResultMsg processLogin(String key,Class extends LoginAdapter> clazz){
-
- try {
- LoginAdapter adapter = clazz.newInstance();
- if(adapter.support(adapter)){
- return adapter.login(key,adapter);
- }else{
- return null;
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- return null;
- }
- }
客户端测试代码
- package com.ruoyi.demo.designPattern.adapterPattern;
-
- public class PassportTest {
- public static void main(String[] args) {
- IPassportForThird passportForThird = new PassportForThirdAdapter();
- passportForThird.loginForQQ("");
- }
- }
适配器模式主要解决的是功能兼容问题,单场景适配时不会和策略模式对比,但是
多场景适配时容易混淆。
上面给每个适配器都加上了一个support()方法,用来判断是否兼容。
设计模式-简单工厂模式、工厂模式、抽象工厂模式在Java中的使用示例:
设计模式-简单工厂模式、工厂模式、抽象工厂模式在Java中的使用示例_霸道流氓气质的博客-CSDN博客
设计模式-策略模式在Java中的使用示例: