Adapter Pattern
将两个不兼容的类纠合在一起使用,属于结构型模式,需要有Adaptee(被适配者)和Adaptor(适配器)两个身份
我们经常碰到要将两个没有关系的类组合在一起使用,第一解决方案是:修改各自类的接口,但是如果我们没有源代码,或者,我们不愿意为了一个应用而修改各自的接口。 怎么办?
使用Adapter,在这两种接口之间创建一个混合接口(混血儿).
**个人理解:**其实就是一种兼容性思维,Adaptor 要把Adaptee 干的是通过自己转化一次,因为 Adaptee 不满足相关的接口需要,但是Adaptor 满足,而 Adaptor 只是起到了中间人的角色,真正干活还是调用的 Adaptee 的方法
实现Adapter方式,其实"think in Java"的"类再生"一节中已经提到,有两种方式:组合(composition)和继承(inheritance).
假设我们要打桩,有两种接口:
方形桩
public interface ISquarePeg {
public void insert(String str);
}
圆形桩
public interface IRoundPeg {
public void insertIntoHole(String msg);
}
各自有一个实现类
public class SquarePeg implements ISquarePeg {
public void insert(String str){
System.out.println("SquarePeg insert():"+str);
}
}
public class RoundPeg implements IRoundPeg {
public void insertIntoHole(String msg) {
System.out.println("RoundPeg insertIntoHole():"+msg);
}
}
现在有一个需求,要在打圆形桩的方法里面干打方形桩的活(这就是适配),那么可以通过如下的继承关系来实现
public class PegAdapter extends SquarePeg implements IRoundPeg {
public void insertIntoHole(String str){ super.insert(str);} //在圆形桩的方法里干打方形桩的活
}
从这个例子也可以看出,使用适配器模式最好是 Adaptor 和 Adaptee 的适配方法的参数和返回值相同或者相近,当然不符合这个条件也是没有问题的,因为方法的封装本身就可以做很多兼容性处理。
或者可以在打原型桩的类中持有打方形桩的对象
public class PegAdapter implements IRoundPeg {
private ISquarePeg squarePeg;
public PegAdapter(ISquarePeg squarePeg) {
this.squarePeg = squarePeg;
}
@Override
public void insertIntoHole(String msg) {
this.squarePeg.insert(msg); //持有 Adaptee 的引用,让引用干活
}
}
可以动态的获取几个adapters中一个。使用Reflection技术,可以动态的发现类中的Public方法。
比如我们有一个登陆接口
public interface LoginAdapter {
boolean support(Object adapter);
String login(String id, Object adapter);
}
有多个实现类,有QQ登陆:
public class LoginForQQAdapter implements LoginAdapter {
public boolean support(Object adapter) {
return adapter instanceof LoginForQQAdapter;
}
public String login(String id, Object adapter) {
return "QQ登陆成功";
}
}
有微信登陆
public class LoginForWechatAdapter implements LoginAdapter {
public boolean support(Object adapter) {
return adapter instanceof LoginForWechatAdapter;
}
public String login(String id, Object adapter) {
return "微信登陆成功";
}
}
。。。
还有很多其他的登陆方式,这个时候,我们可以这样来做一个动态的,支持无限扩展的适登陆适配器
private String processLogin(String key,Class<? extends LoginAdapter> clazz){
try{
//适配器不一定要实现接口
LoginAdapter adapter = clazz.newInstance();
//判断传过来的适配器是否能处理指定的逻辑
if(adapter.support(adapter)){
return adapter.login(key,adapter);
}
}catch (Exception e){
e.printStackTrace();
}
return "登陆失败";
}
上面的代码其实就有些Spring中
Spring AOP 中 AdvisorAdapter
public interface AdvisorAdapter {
boolean supportsAdvice(Advice var1);
MethodInterceptor getInterceptor(Advisor var1);
}
这种写法是不是有上面loginAdaptor的影子,它有三个实现类MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter 和
ThrowsAdviceAdapter。看下MethodBeforeAdviceAdapter 类
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
MethodBeforeAdviceAdapter() {
}
public boolean supportsAdvice(Advice advice) {
return advice instanceof MethodBeforeAdvice;
}
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice)advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
其适配调用的关键代码还是在DispatcherServlet 的doDispatch()方法中,doDispatch()方法调用了getHandlerAdapter()方法,代码如下:
protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
if(this.handlerAdapters != null) {
Iterator var2 = this.handlerAdapters.iterator();
while(var2.hasNext()) {
HandlerAdapter ha = (HandlerAdapter)var2.next();
if(this.logger.isTraceEnabled()) {
this.logger.trace("Testing handler adapter [" + ha + "]");
}
if(ha.supports(handler)) { //在这里判断各适配器是否兼容
return ha;
}
}
}
throw new ServletException("No adapter for handler [" + handler + "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
}