适配器模式
定义
适配器模式(Adapter Pattern)是指将一个类的接口转换成客户期望的另一个接口,使原本的接口不兼容的类可以一起工作。
属于结构性设计模式。
现实生活中的适配器:
适用场景
- 已经存在的类,它的方法和需求不匹配(方法结果相同或相似)的情况;
- 适配器不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不同厂家造成功能类似而接口不相同情况下的解决方案。
案例一:220V和5V 交流电的转换
UML类图
代码实现
AC220 类
public class AC220 {
public int outputPower220V() {
int output = 220;
System.out.println("输出电流" + output + "V");
return output;
}
}
DC5 接口
public interface DC5 {
/**
* 将220伏转换为5V
* @return
*/
int outputDC5();
}
PowerAdapter 类
public class PowerAdapter implements DC5 {
private AC220 powerAc220;
public PowerAdapter(AC220 powerAc220) {
this.powerAc220 = powerAc220;
}
@Override
public int outputDC5() {
int adapterInput = powerAc220.outputPower220V();
int adapterOutput = adapterInput / 44;
System.out.println("使用PowerAdapter输入AC:" + adapterInput + "V,输出DC:" + adapterOutput + "V");
return adapterOutput;
}
}
测试类
public class PowerAdapterTest {
public static void main(String[] args) {
DC5 dc5 = new PowerAdapter(new AC220());
dc5.outputDC5();
}
}
案例二:多平台登录注册功能
UML类图
代码实现
Member
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;
}
}
ResultMsg
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;
}
}
LoginAdapter
public interface LoginAdapter {
/**
* 是否支持当前功能
*
* @param adapter 适配器
* @return 是否支持
*/
boolean support(Object adapter);
/**
* 登录
* @param id 用户Id
* @param a
* @return 登陆结果
*/
ResultMsg login(String id, Object a);
}
LoginForQQAdapter
public class LoginForQQAdapter implements LoginAdapter {
@Override
public boolean support(Object adapter) {
return adapter instanceof LoginForQQAdapter;
}
@Override
public ResultMsg login(String id, Object a) {
return null;
}
}
LoginForWechatAdapter
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;
}
}
RegistAdapter
public interface RegistAdapter {
/**
* 是否支持当前功能
*
* @param adapter 适配器
* @return 是否支持
*/
boolean support(Object adapter);
/**
* 注册
*
* @param id
* @param adapter
* @return
*/
ResultMsg register(String id, Object adapter);
}
RegistForQQAdapter
public class RegistForQQAdapter implements RegistAdapter, LoginAdapter {
@Override
public boolean support(Object adapter) {
return adapter instanceof RegistForQQAdapter;
}
@Override
public ResultMsg register(String id, Object adapter) {
return null;
}
@Override
public ResultMsg login(String id, Object adapter) {
return null;
}
}
IPassportForThird
public interface IPassportForThird {
/**
* QQ登录
* @param id
* @return
*/
ResultMsg loginForQQ(String id);
/**
* 微信登录
* @param id
* @return
*/
ResultMsg loginForWechat(String id);
/**
* 注册后自动登录
* @param username
* @param passport
* @return
*/
ResultMsg loginForRegister(String username, String passport);
}
SignInService
public class SignInService {
/**
* 注册方法
*
* @param username 用户名
* @param password 密码
* @return
*/
public ResultMsg register(String username,String password){
return new ResultMsg(200,"注册成功",new Member());
}
/**
* 登录的方法
*
* @param username 用户名
* @param password 密码
* @return
*/
public ResultMsg login(String username,String password){
return null;
}
}
PassportForThirdAdapter
/**
* <p> @Title PassportForThirdAdapter
* <p> @Description 兼容多平台登录接口适配器 结合策略模式、工厂模式、适配器模式
*
*/
public class PassportForThirdAdapter extends SignInService implements IPassportForThird {
@Override
public ResultMsg loginForQQ(String id) {
// 如果不使用support()方法,即使使用RegiterForQQAdapter的话也会正常调用login()
// return processLogin(id, RegistForQQAdapter.class);
return processLogin(id, LoginForQQAdapter.class);
}
@Override
public ResultMsg loginForWechat(String id) {
return processLogin(id, LoginForWechatAdapter.class);
}
@Override
public ResultMsg loginForRegister(String username, String password) {
super.register(username, password);
return super.login(username, password);
}
private ResultMsg processLogin(String key, Class<? extends LoginAdapter> clazz) {
try {
// 适配器不一定要实现接口
LoginAdapter adapter = clazz.newInstance();
// 判断传过来的适配器是否能处理指定的逻辑
if (adapter.support(adapter)) {
return adapter.login(key, adapter);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
测试类
public class PassportTest {
public static void main(String[] args) {
PassportForThirdAdapter passportForThird = new PassportForThirdAdapter();
passportForThird.loginForQQ("234234234");
}
}
在源码中的体现
Spring-AOP 的 AdvisorAdapter
Spring-Web 的 HandlerAdapter
适配器模式的优点
- 能提高类的透明性和复用,现有的类复用但不需要改变;
- 目标类和适配器类解耦,提高程序的扩展性;
- 在很多业务场景中符合开闭原则。
适配器模式的缺点
- 适配器编写过程需要全面考虑,可能会增加系统的复杂性;
- 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。