Skip to content

适配器模式支持第三方登录

设配器模式的定义

原本一个类的接口实现的功能,由于需要进行扩展,支持另外一种形式的接口。那么 Adapter 模式使原本由于接口不兼容而不能在一起的类可以一起工作

场景

  1. 使用一个已经存在的类,但她的接口不符合你的需求
  2. 创建一个可以复用的类,该类可以与其他不相关的类或者不可预见的类(即那些接口,可能不一定兼容的类)协同工作
  3. (仅适用于对象 Adapter)使用一些已经存在的子类,但是不可能对每一个都进行 子类化以匹配它们的接口。对象适配器可以适配它的父类接口

参与者

  1. Target 定义 Client 需要使用与特定领域相关的接口
  2. Client 与符合 Target 接口对象一致
  3. Adaptee 定义一个已经存在的类,这个接口需要适配
  4. Adapter 对 Adaptee 的接口与 Target 接口进行适配

登录功能改造

场景: 我们原本只支持用户名+密码登录, 那么现在我们需要其支持第三方登录,但是最后面核心功能还是通过用户名 + 密码登录,但是第三方登录的入参完全不一样, 那么我们就可以通过定义一个设配器来完成登录功能的改造,而不影响其原本的登录功能

目标对象 Target 定义

目标对象 Target 是 client 要使用的接口对象

java
/**
 * 目标角色
 */
public interface Login3rdTarget {

    String loginByGitee(String code,String state);

    String loginByWechat(String ...params);

    String loginByQQ(String ...params);

    String loginDefault(String username,String password);
}

源对象 Adaptee

源对象需要被适配的不兼容对象,也就是 UserService

java
@Service
public class UserService {

    private final UserRepository userRepository;

    public UserService(UserRepository userRepository) {
        this.userRepository = userRepository;
    }


    public String login(String account,String password) {
        UserInfo userInfo = userRepository.findByUsernameAndUserPassword(account, password);
        if (userInfo == null) {
            return "account/ password error";
        }
        return "Login Success";
    }

    public String register(UserInfo userInfo) {
        if (checkUserExist(userInfo.getUsername())) {
            throw new RuntimeException("user already registed");
        }
        userInfo.setCreateTime(new Date());
        userRepository.save(userInfo);
        return "register success";
    }

    public boolean checkUserExist(String username) {
        UserInfo userInfo = userRepository.findByUsername(username);
        if (userInfo == null){
            return false;
        }
        return true;
    }
}

设配器对象 Adapter

充当中间转换角色,该对象将源对象转换成目标接口,也就是我们的 Login3rdAdapter

java
@Component
public class Login3rdAdapter extends UserService implements Login3rdTarget {

    public Login3rdAdapter(UserRepository userRepository) {
        super(userRepository);
    }

    @Override
    public String loginByGitee(String code, String state) {

        // 根据code 请求gitee 获取 access_token

        // 根据access_token 获取用户信息
        JSONObject userInfo = new JSONObject(); // 假设这个就是gitee返回回来的数据
        String username = "gitee@" + userInfo.get("name");
        String password = username;
        return autoRegister3rdAndLogin(username,password);
    }

    private String autoRegister3rdAndLogin(String username, String password) {
        if (super.checkUserExist(username)) {
            // 如果第三方账号已注册, 直接登录
            return super.login(username,password);
        }
        UserInfo userInfo = new UserInfo();
        userInfo.setUsername(username);
        userInfo.setUserPassword(password);
        userInfo.setCreateTime(new Date());
        super.register(userInfo);
        return super.login(username,password);
    }

    @Override
    public String loginByWechat(String... params) {
        return null;
    }

    @Override
    public String loginByQQ(String... params) {
        return null;
    }

    @Override
    public String loginDefault(String username, String password) {
        return super.login(username,password);
    }
}

Client 调用方

UserController 也就是我们的调用方

java
@RestController
public class UserController {

    private final Login3rdAdapter login3rdAdapter;


    public UserController(Login3rdAdapter login3rdAdapter) {
        this.login3rdAdapter = login3rdAdapter;

    }

    @PostMapping("login")
    public String login(@RequestParam String account, @RequestParam String password) {
        return login3rdAdapter.login(account, password);
    }

    @PostMapping("register")
    public String register(@RequestBody UserInfo userInfo) {
        return login3rdAdapter.register(userInfo);
    }

    @PostMapping("login/gitee")
    public String loginByGitee(@RequestParam String code,@RequestParam String state) {
        return login3rdAdapter.loginByGitee(code, state);
    }
}

从上述我们可以看到,我们通过 Adapter 完成了用户登录接口的改造

uml 类图

Adapter UML 类图

设用场景

  1. 重用现有的代码:适配器模式可以允许我们重用已有的类或接口,而不需要修改其原有的代码
  2. 集成老系统:当现有的系统不满足用户需求时,需要增加系统功能或接口。但是,老系统的接口可能与现有的技术、平台不兼容,此时可以采用适配器模式,将现有的接口适配为新的接口,从而实现新系统的集成。
  3. 集成第三方组件:在使用第三方组件时,可能由于它们实现的 API 不同而导致应用程序复杂,此时可以使用适配器模式,将第三方组件提供的 API 适配为自己需要的 API,方便在应用程序中进行调用
  4. 实现跨平台兼容:在不同平台、不同技术栈之间进行开发时,常常需要适配不同的接口,以使得不同的平台或技术栈之间能够相互兼容,此时可以使用适配器模式来处理各种不兼容问题。

Released under the MIT License.