适配器模式的定义:将一个类的接口转换成客户端需要的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。属于结构型设计模式。
适配器模式分为类适配器、对象适配器和接口适配器。
适配器模式的结构:适配器模式(Adapter)包含3个主要角色。
- 目标(Target)角色:系统业务所期待的接口,它可以是抽象类或接口。
- 适配者(Adaptee)角色:等待被适配的对象。
- 适配器(Adapter)类:它是一个转换器,把适配者角色转换成目标角色。
类适配器的实现:类适配器是通过继承来实现适配功能。
//适配者角色
public class Adaptee {
public void doSomeThing(){
System.out.println("适配者角色要做事了!!!");
}
}
//目标角色
public interface Target {
void request();
}
//适配器类
public class ClassAdapter extends Adaptee implements Target{
@Override
public void request() {
doSomeThing();
System.out.println("适配器要将适配者角色做转换了!!!");
}
}
//测试类
public class ClassAdapterTest {
public static void main(String[] args) {
Target target = new ClassAdapter();
target.request();
}
}
类适配器的结构图
对象适配器的实现:对象适配器是通过组合来实现适配功能。
//适配者角色
public class Adaptee {
public void doSomeThing(){
System.out.println("适配者角色要做事了!!!");
}
}
//目标角色
public interface Target {
void request();
}
//适配器类
public class ObjectAdapter implements Target{
private Adaptee adaptee;
public ObjectAdapter(Adaptee adaptee){
this.adaptee = adaptee;
}
@Override
public void request() {
adaptee.doSomeThing();
System.out.println("适配器要将适配者角色做转换了!!!");
}
}
//测试类
public class ObjectAdapterTest {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new ObjectAdapter(adaptee);
target.request();
}
}
对象适配器的结构图:
接口适配器的实现:接口适配器用于需要转换的接口方法过多的情况,此时若使用类适配器或对象适配器会产生大量的适配器类,系统会显得复杂和臃肿。
//适配者角色
public class Adaptee {
public void doSomeThing(){
System.out.println("适配者角色要做事了!!!");
}
}
//目标角色
public interface Target {
void request1();
void request2();
void request3();
void request4();
void request5();
}
//适配器类
public class Adapter implements Target{
private Adaptee adaptee;
public Adapter(Adaptee adaptee){
this.adaptee = adaptee;
}
@Override
public void request1() {
adaptee.doSomeThing();
System.out.println("适配器要将适配者角色做转换成目标对象1");
}
@Override
public void request2() {
adaptee.doSomeThing();
System.out.println("适配器要将适配者角色做转换成目标对象2");
}
@Override
public void request3() {
adaptee.doSomeThing();
System.out.println("适配器要将适配者角色做转换成目标对象3");
}
@Override
public void request4() {
adaptee.doSomeThing();
System.out.println("适配器要将适配者角色做转换成目标对象4");
}
@Override
public void request5() {
adaptee.doSomeThing();
System.out.println("适配器要将适配者角色做转换成目标对象5");
}
}
//测试类
public class AdapterTest {
public static void main(String[] args) {
Adaptee adaptee = new Adaptee();
Target target = new Adapter(adaptee);
target.request1();
target.request2();
target.request3();
target.request4();
target.request5();
}
}
接口适配器的结构图:
适配器模式的应用实例:模拟系统第三方登录,分别使用QQ/微信/微博三种方式登录。
//登录返回结果
public class ResultMsg {
private int code;
private String msg;
public ResultMsg(int code,String msg){
this.code = code;
this.msg = msg;
}
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 class LoginService {
public ResultMsg login(String username,String password){
return new ResultMsg(200,"登录成功~");
}
}
//登录适配器接口
public interface LoginAdapter {
boolean support(Object object);
ResultMsg login(Object[] username,Object adapter);
}
//抽象登录适配器,实现公共登录方法
public abstract class AbstractAdapter extends LoginService implements LoginAdapter{
public ResultMsg login(Object[] id, Object adapter) {
if(support(adapter)){
return super.login(id.toString(), null);
}
return new ResultMsg(1111,"未支持的登录方式!!!");
}
}
//QQ登录适配器,实现校验逻辑
public class LoginForQQAdapter extends AbstractAdapter{
@Override
public boolean support(Object adapter) {
return adapter instanceof LoginForQQAdapter;
}
}
//微信登录适配器,实现校验逻辑
public class LoginForWeChatAdapter extends AbstractAdapter{
@Override
public boolean support(Object adapter) {
return adapter instanceof LoginForWeChatAdapter;
}
}
//微博登录适配器,实现校验逻辑
public class LoginForWeiboChatAdapter extends AbstractAdapter{
@Override
public boolean support(Object adapter) {
return adapter instanceof LoginForWeiboChatAdapter;
}
}
//第三方登录接口
public interface ILoginForThird {
ResultMsg loginForQQ(Object[] openId);
ResultMsg loginForWechat(Object[] openId);
ResultMsg loginForWeibo(Object[] openId);
}
//第三方登录实现类
public class LoginForThirdAdapter implements ILoginForThird{
@Override
public ResultMsg loginForQQ(Object[] openId) { return loginForThird(openId,new LoginForQQAdapter()); }
@Override
public ResultMsg loginForWechat(Object[] openId) {
return loginForThird(openId,new LoginForWeChatAdapter());
}
@Override
public ResultMsg loginForWeibo(Object[] openId) {
return loginForThird(openId,new LoginForWeiboChatAdapter());
}
private ResultMsg loginForThird(Object[] openId,LoginAdapter adapter){
if(adapter.support(adapter)){
return adapter.login(openId,adapter);
}
return null;
}
}
//测试类
public class Test {
public static void main(String[] args) {
LoginForThirdAdapter adapter = new LoginForThirdAdapter();
ResultMsg resultMsg = adapter.loginForQQ(new Object[]{"96e79218965eb72c92a549dd5a330112"});
System.out.println(resultMsg.getMsg());
}
}
第三方登录应用实例的结构图:
适配器模式的优点:
- 复用了现存的类,不需要修改原有代码而重用现有的适配者类。
- 将目标类和适配者类解耦,提供程序的扩展性。
- 在很多业务场景中符合开闭原则。
适配器模式的缺点是:
- 适配器编写过程需要结合业务场景全面考虑,可能会增加系统的复杂性。
- 增加代码阅读难度,降低代码可读性,过多使用适配器会使系统代码变得凌乱。
适配器模式适用的场景:
- 已经存在满足新系统功能需求的类,但其接口同新系统的接口不一致。
- 使用第三方提供的组件,但组件接口定义和自己要求的接口定义不同。