场景
适配器模式(Adapter Pattern)
是指将一个类的接口转换为用户期望的另一个接口,使原本接口不兼容的类可以一起工作。
适用场景:
1、已经存在的类的方法和需求不匹配(方法结果相同或类似)的情况。
2、适配器模式不是软件初始阶段考虑的设计模式,是随着软件的发展,由于不同产品、不同厂家
造成功能类似而接口不同的问题的解决方案。
3、生活中类似的场景比如电源插座转换头、手机充电转换头、显示器转换头、电压转换等。
注:
博客:
https://blog.csdn.net/badao_liumang_qizhi
关注公众号
霸道的程序猿
获取编程相关电子书、教程推送与免费下载。
适配器模式示例-电压转换
民用电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中的使用示例:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/127539695
设计模式-策略模式在Java中的使用示例:
https://blog.csdn.net/BADAO_LIUMANG_QIZHI/article/details/127622238