适配器模式:
适配器模式主要解决的是功能兼容问题。
将一个类的接口转换成客户期望的另一个接口,使 原本的接口不兼容的类可以一起工作,属于结构型设计模式。
适配器适用于以下几种业务场景:
1、已经存在的类,它的方法和需求不匹配(方法结果相同或相似)的情况。
2、适配器模式不是软件设计阶段考虑的设计模式,是随着软件维护,由于不同产品、不 同厂家造成功能类似而接口不相同情况下的解决方案。有点亡羊补牢的感觉。
实际场景:
电源插转换头、手机充电转换头、显示器转接头、适配新的登录方式(以前是用户名+密码登录,现在提供qq微信手机号等第三方登录)
设计原则 | 简称 | 解释说明 | 备注 |
开闭原则 | (OCP)Open-Closed Principle, | 对扩展开放,对修改关闭。 | |
依赖倒置原则 | (DIP)Dependence Inversion Principle | 高层模块不应该依赖底层模块,二者都应该依赖其抽象。也就是说针对接口编程,不要针对实现编程,针对接口编程包括使用接口或抽象类,这样可以使得各个模块彼此独立,降低模块间的耦合性。而且在实现类中尽量不发生直接的依赖关系,依赖关系通过接口或抽象类产生。 | |
单一职责原则 | (SRP)Single Responsibility Principle | 一个类、接口、方法只做一件事。 | |
接口隔离原则 | (ISP)Interface Segregation Principle, | 尽量保证接口的纯洁性,客户端不应该依赖不需要的接口。胖接口会导致他们的客户程序之间产生不正常的并且有害的耦合关系.当一个客户程序要求该胖接口进行一个改动时,会影响到所有其他的客户程序.因此客户程序应该仅仅依赖他们实际需要调用的方法. | |
迪米特法则 | (LoD)Law of Demeter 又叫做最少知识原则(LKP)Least Knowledge Principle, | 又叫最少知道原则,一个类对其所依赖的类知道得越少越好。就是说,如果两个类不必彼此直接通信,那么这两个类就不应当发生直接的相互作用,如果其中的一个类需要调用另一个类的某一个方法的话,可以通过第三者转发这个调用。 | |
里氏替换原则 | (LSP)Liskov Substitution Principle, | 子类可以扩展父类的功能但不能改变父类原有的功能。一般而言,如果有两个具体类A,B有继承关系,那么一个最简单的修改方案是建立一个抽象类C,然后让类A和B成为抽象类C的子类. | |
合成复用原则 | (CARP)Composite/Aggregate Reuse Principle, | 尽量使用对象组合、聚合,而不使用继承关系达到代码复用的目的。 |
关系图
上代码:
public class ResultMsg {
private int status;
private String code;
private String msg;
public int getStatus() {
return status;
}
public void setStatus(int status) {
this.status = status;
}
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
}
public class OldLoginService {
public ResultMsg login(String id){
return null;
}
public ResultMsg regist(String id){
return null;
}
}
public interface LoginAdapter {
public boolean support(Object adapter);
public ResultMsg login(String id,Object adapter);
}
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;
}
}
public class LoginForTelAdapter implements LoginAdapter {
@Override
public boolean support(Object adapter) {
return adapter instanceof LoginForTelAdapter;
}
@Override
public ResultMsg login(String id, Object adapter) {
return null;
}
}
public class LoginForWeChartAdapter implements LoginAdapter {
@Override
public boolean support(Object adapter) {
return adapter instanceof LoginForWeChartAdapter;
}
@Override
public ResultMsg login(String id, Object adapter) {
return null;
}
}
//建第三方登录兼容接口
public interface IPassportForThird {
ResultMsg loginForQQ(String id);
ResultMsg loginForTel(String id);
ResultMsg loginForWeChart(String id);
}
package adapter.dengLu;
//兼容第三方的adapter
public class PassportForThirdAdapter extends OldLoginService implements IPassportForThird{
@Override
public ResultMsg loginForQQ(String id) {
return processLogin(id,LoginForQQAdapter.class);
}
@Override
public ResultMsg loginForTel(String id) {
return processLogin(id,LoginForTelAdapter.class);
}
@Override
public ResultMsg loginForWeChart(String id) {
return processLogin(id,LoginForWeChartAdapter.class);
}
//这里用到了简单工厂模式及策略模式
private ResultMsg processLogin(String id,Class<? extends LoginAdapter> clazz){
try {
LoginAdapter loginAdapter = clazz.newInstance();
if(loginAdapter.support(loginAdapter)){
return loginAdapter.login(id,loginAdapter);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
return null;
}
}
package adapter.dengLu;
public class Test {
public static void main(String[] args) {
IPassportForThird passportForThird = new PassportForThirdAdapter();
passportForThird.loginForQQ("");
passportForThird.loginForTel("");
passportForThird.loginForWeChart("");
}
}
适配器模式的优缺点
优点:
1、能提高类的透明性和复用,现有的类复用但不需要改变。
2、目标类和适配器类解耦,提高程序的扩展性。
3、在很多业务场景中符合开闭原则。
缺点:
1、适配器编写过程需要全面考虑,可能会增加系统的复杂性。
2、增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。