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

对于一些老系统应该都有登录接口,但是随着业务的发展和社会的进步,单纯地依赖用户名密码登录显然不能满足用户需求了。现在,我们大部分系统都已经支持多种登录方式,如QQ登录,微信登录,手机登录,微博登录等等,同时保留用户名密码的登录方式。虽然登录形式丰富了,但是登录后的处理逻辑可以不必改,同样是将登录状态保存到session,遵循开闭原则。
首先创建统一的返回结果

ResultMsg类

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class ResultMsg {
    private int code;
    private String msg;
    private Object data;

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

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }
}

假设老系统的登录逻辑SiginService

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class SiginService {
    /**
     * 注册方法
     */
    public ResultMsg regist(String username,String password){
        return new ResultMsg(200,"注册成功",new Member());
    }
    /**
     * 登录方法
     */
    public ResultMsg login(String username,String password){
        return null;
    }
}

相关的Member实体类

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class Member {
    private String username;
    private String password;
    private String mid;
    private String info;

    public String getMid() {
        return mid;
    }

    public void setMid(String mid) {
        this.mid = mid;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getInfo() {

        return info;
    }

    public void setInfo(String info) {
        this.info = info;
    }
}

创建一个新的类继承原来的逻辑,运行非常稳定的代码我们不去改动

package loginadapter;

/**稳定的方法不去动,直接继承下来
 * Created by Lenovo on 2019-7-18.
 */
public class SigninForThirdService extends SiginService {
    public ResultMsg loginForQQ(String openId){
        //1.openId是全局唯一的,我们可以把它当作一个用户
        //2.密码默认为QQ_EMPTY
        //3.注册(在原有系统里面创建一个用户)
        //4.调用原来的登录方法
        return  loginForRegist(openId,null);
    }
    public ResultMsg loginForWechat(String openId){
        return null;
    }
    public ResultMsg loginForToken(String token){
        //通过Token拿到用户信息,然后再重新登录一次
        return null;
    }
    public ResultMsg loginForRegist(String username,String password){
        super.regist(username, null);
        return super.login(username,null);
    }
}

测试类:

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class SigninForThirdServiceTest {
    public static void main(String[] args){
        SigninForThirdService service=new SigninForThirdService();
        //不改变原来的代码,也要能够兼容新的需求
        //还可以再加一层策略模式
        service.loginForQQ("ssddfsdgsdsgs");
    }
}

通过一个简单的适配,完成了代码兼容。当然,我们代码还可以更加优雅,根据不同的登录方式,创建不同的Adapter。首先,创建LoginAdapter接口:

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public interface LoginAdapter {
    boolean support(Object adapter);
    ResultMsg login(String id,Object adapter);
}

下面分别实现不同的登录适配:
QQ

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class LoginForQQAdapter implements LoginAdapter {
    @Override
    public ResultMsg login(String id, Object adapter) {
        return null;
    }

    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForQQAdapter;
    }
}

微博

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class LoginForSinaAdapter implements LoginAdapter {
    @Override
    public ResultMsg login(String id, Object adapter) {
        return null;
    }

    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForSinaAdapter;
    }
}

手机号

   package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class LoginForTelAdapter implements LoginAdapter {
    @Override
    public ResultMsg login(String id, Object adapter) {
        return null;
    }

    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForSinaAdapter;
    }
}

Token

 package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class LoginForTokenAdapter implements LoginAdapter {
    @Override
    public boolean support(Object adapter) {
        return adapter instanceof LoginForTokenAdapter;
    }

    @Override
    public ResultMsg login(String id, Object adapter) {
        return null;
    }
}

微信

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
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;
    }
}

创建第三方登录兼容接口

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public interface IPassportForThird {
    /**
     * QQ登录
     * @param id
     * @return
     */
    ResultMsg loginForQQ(String id);
    /**
     * 微信登录
     * @param id
     * @return
     */
    ResultMsg loginForWechat(String id);

    /**
     * 记录登录状态后自动登录
     * @param token
     * @return
     */
    ResultMsg loginForToken(String token);

    /**
     * 手机号登录
     * @param telphone
     * @param code
     * @return
     */
    ResultMsg loginForTelphone(String telphone,String code);

    /**
     * 注册后自动登录
     * @param username
     * @param passport
     * @return
     */
    ResultMsg loginForRegister(String username,String passport);

}

实现兼容

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class PassportForThirdAdapter extends SiginService implements IPassportForThird {
    @Override
    public ResultMsg loginForQQ(String id) {
        return processLogin(id,LoginForQQAdapter.class);
    }

    @Override
    public ResultMsg loginForWechat(String id) {
        return processLogin(id,LoginForWechatAdapter.class);
    }

    @Override
    public ResultMsg loginForToken(String token) {
        return processLogin(token,LoginForTokenAdapter.class);
    }

    @Override
    public ResultMsg loginForTelphone(String telphone, String code) {
        return processLogin(telphone, LoginForTelAdapter.class);
    }
    public ResultMsg loginForRegister(String username, String passport) {
        super.regist(username,null);
        return super.login(username,null);
    }
    //这里用到了简单工厂模式以及策略模式
    private ResultMsg processLogin(String key,Class<? extends LoginAdapter> clazz) {
        try {
            LoginAdapter adapter = clazz.newInstance();
            if (adapter.support(adapter)) {
                return adapter.login(key, adapter);
            } else {
                return null;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
}

最后的测试类

package loginadapter;

/**
 * Created by Lenovo on 2019-7-18.
 */
public class PassportTest {
    public static void main(String[] args){
        IPassportForThird passportForThird=new PassportForThirdAdapter();
        passportForThird.loginForQQ("");
    }
}

注:适配器模式主要解决的是功能兼容的问题,单场景的适配和策略不会有对比,但是多场景的适配可能会产生联想和混淆。其实此处我在每个适配器上都加了一个support,用来判断是否兼容,support方法的参数也是Object的,而support来自于接口。适配器的实现逻辑并不依赖于接口,完全可以将LoginAdapter接口去掉。上面的代码也可以说是策略模式,简单工厂模式和适配器模式的综合应用,LoginAdapter接口这里体现策略模式的思想,实现兼容 的PassportForThirdAdapter类中的processLogin方法体现了适配器模式的思想,里面的实现体现了简单工厂的思想。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值