zoukankan      html  css  js  c++  java
  • 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());
        }
    
        public ResultMsg login(String userName, String passWord) {
            return null;
        }
    }
    复制代码

      为了遵循开闭原则,我们不修改老系统代码,下面是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
        public ResultMsg login(String id, Object adapter) {
            return null;
        }
    }
    复制代码

      微信登录:

    复制代码
    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;
        }
    }
    复制代码

      接着,创建第三方登录兼容接口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
        public ResultMsg loginForWechat(String id) {
            return null;
        }
    
        @Override
        public ResultMsg loginForResist(String userName, String passWord) {
            super.regist(userName, passWord);
            return super.login(userName, passWord);
        }
    
        //这里使用简单工厂及策略模式
        private ResultMsg procssLogin(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 null;
        }
    }
    复制代码

      前面每个适配器都加上了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;
    
        public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
            Assert.notNull(advice, "Advice must not be null");
            this.advice = advice;
        }
    
        public Object invoke(MethodInvocation mi) throws Throwable {
            this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis());
            return mi.proceed();
        }
    }
    复制代码

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

    四、适配器模式的优缺点

      优点:

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

      缺点:

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

    转载于:https://www.cnblogs.com/xcgShare/p/12190642.html

  • 相关阅读:
    SQL Server 2008中的hierarchyid
    SQL判断空值、nvl处理与JOIN的使用
    Transact-SQL语法速查手册
    MySQL连接字符串
    如何让spark sql写mysql的时候支持update操作
    基于calcite做傻瓜式的sql优化(三)
    基于calcite做傻瓜式的sql优化(二)
    基于calcite做傻瓜式的sql优化(一)
    spark升级:从1.6升级到2.4.6的记录
    彻底解决,sparkSQL读取csv中Map字段类型的问题
  • 原文地址:https://www.cnblogs.com/it-deepinmind/p/13254635.html
Copyright © 2011-2022 走看看