9°

Spring中常见的设计模式——适配器模式

一、适配器模式的应用场景  

  适配器模式(Adapter Pattern)是指将一个类的接口转换成用户期待的另一个接口,使原本接口不兼容的类可以一起工作,属于构造设计模式。

  适配器适用于以下几种业务场景:

  • 已经存在的类的方法和需求不匹配(方法结果相同或相似)的情况。
  • 适配器模式不是软件初始阶段应该考虑的设计模式,是随着软件的开发,由于不同产品、不同厂家造成功能类似而接口不同的问题的解决方案,有点亡羊补牢的感觉。

二、重构第三方登录自由适配的业务场景

  将原来的单一支持用户名和密码登录,扩展为可以支持微信和手机登录。

  创建统一返回结果ResultMsg:

@Data
public class ResultMsg {
private Integer code;
private String msg;
private Object data;

public ResultMsg(Integer code, String msg, Object data) {
this.code = code;
this.data = data;
this.msg = msg;
}
}

  老系统登录代码如下:

public class SignInService {
    public ResultMsg regist(String userName, String passWord) {
        return new ResultMsg(200, "注册成功", new Member());
    }
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> ResultMsg login(String userName, String passWord) {
    </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
}

}

  为了遵循开闭原则,我们不修改老系统代码,下面是Member类:

@Data
public class Member {
    private String userName;
    private String passWord;
    private String mid;
    private String info;
}

  我们优雅的根据不同登录方式创建不同的“Adapter”,首先创建LoginAdapter:

public interface LoginAdapter {
    boolean support(Object adapter);
ResultMsg login(String id, Object adapter);

}

  手机登录:

public class LoginForTelAdapter implements LoginAdapter {
    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForTelAdapter;
    }
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> ResultMsg login(String id, Object adapter) {
    </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
}

}

  微信登录:

public class LoginForWechatAdapter implements LoginAdapter {
    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForWechatAdapter;
    }
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> ResultMsg login(String id, Object adapter) {
    </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
}

}

  接着,创建第三方登录兼容接口IPassportForThid:

public interface IPassportForThird {
    ResultMsg loginForTel(String telephone, String code);
ResultMsg loginForWechat(String id);

ResultMsg loginForResist(String userName, String passWord);

}

  实现兼容PassportForThirdAdapter:

public class PassportForThirdAdapter extends SignInService implements IPassportForThird {
    @Override
    public ResultMsg loginForTel(String telephone, String code) {
        return null;
    }
@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> ResultMsg loginForWechat(String id) {
    </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
}

@Override
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> ResultMsg loginForResist(String userName, String passWord) {
    </span><span style="color: #0000ff;">super</span><span style="color: #000000;">.regist(userName, passWord);
    </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">super</span><span style="color: #000000;">.login(userName, passWord);
}

</span><span style="color: #008000;">//</span><span style="color: #008000;">这里使用简单工厂及策略模式</span>
<span style="color: #0000ff;">private</span> ResultMsg procssLogin(String key, Class&lt;? <span style="color: #0000ff;">extends</span> LoginAdapter&gt;<span style="color: #000000;"> clazz) {
    </span><span style="color: #0000ff;">try</span><span style="color: #000000;"> {
        LoginAdapter adapter </span>=<span style="color: #000000;"> clazz.newInstance();
        </span><span style="color: #0000ff;">if</span><span style="color: #000000;"> (adapter.support(adapter)) {
            </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> adapter.login(key, adapter);
        }
    } </span><span style="color: #0000ff;">catch</span><span style="color: #000000;"> (Exception e) {
        e.printStackTrace();
    }
    </span><span style="color: #0000ff;">return</span> <span style="color: #0000ff;">null</span><span style="color: #000000;">;
}

}

  前面每个适配器都加上了support()方法,用来判断箭筒。support()方法的参数也是Object类型,而support()来自接口。适配器并不依赖接口,我们使用接口只是为了代码规范。

三、适配器模式在源码中的体现

  Spring中的AOP中AdvisorAdapter类,它有三个实现:MethodBeforAdviceAdapter、AfterReturnningAdviceAdapter、ThrowsAdviceAdapter。

  先看顶层接口AdviceAdapter的源代码:

public interface AdvisorAdapter {
    boolean supportsAdvice(Advice var1);
MethodInterceptor getInterceptor(Advisor var1);

}

  再看MethodBeforAdviceAdapter:

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, BeforeAdvice, Serializable {
    private final MethodBeforeAdvice advice;
</span><span style="color: #0000ff;">public</span><span style="color: #000000;"> MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
    Assert.notNull(advice, </span>"Advice must not be null"<span style="color: #000000;">);
    </span><span style="color: #0000ff;">this</span>.advice =<span style="color: #000000;"> advice;
}

</span><span style="color: #0000ff;">public</span> Object invoke(MethodInvocation mi) <span style="color: #0000ff;">throws</span><span style="color: #000000;"> Throwable {
    </span><span style="color: #0000ff;">this</span><span style="color: #000000;">.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
    </span><span style="color: #0000ff;">return</span><span style="color: #000000;"> mi.proceed();
}

}

  其他两个类就不看了。Spring会根据不同的AOP配置来使用对应的“Advice”,与策略模式不同的是,一个方法可以同时拥有多个“Advice”。

四、适配器模式的优缺点

  优点:

  • 能提高类的透明性和复用性,现有的类会被复用但不需要改变。
  • 目标类和适配器类解耦,可以提高程序的扩展性。
  • 在很多业务场景中符合开闭原则。

  缺点:

  • 在适配器代码编写过程中需要进行全面考虑,可能会增加系统复杂度。
  • 增加代码阅读难度,过多使用适配器会使系统代码变得凌乱。

  

本文转载自博客园,原文链接:https://www.cnblogs.com/xcgShare/p/12190642.html

全部评论: 0

    我有话说: