youyichannel

志于道,据于德,依于仁,游于艺!

0%

适配器模式

适用于对项目进行扩展,适配器模式的好处是不修改原有逻辑进行功能扩展,但是随着功能的增加,适配器的适配种类也会增多。

适用场景:在原有账号密码登录的基础上实现第三方登录。

简介

适配器模式,一个用于将一类的接口适配成用户所期待的接口,能够帮助不兼容的接口变得兼容。

实现

适配器模式的做法是将类自身的接口包裹在一个已经存在的类中,包裹的形式可以是组合,也可以是继承,这里可以分成适配器的两种模式:

  • 对象适配器模式:适配器关联一个它包裹的类实例(成员变量)
  • 类适配器模式:适配器继承被适配的类(一般使用继承的方式)

案例

假设我们现在有接入层UserController、逻辑层UserService和持久层UserRepository,其中UserService类承载了当前注册register和登录login的功能的核心逻辑。

@Service
public class UserService {

@Autowired
private UserRepository userRepository;

public Object login(String... params) {
// ...
}

public String register(String... params) {
// ...
}
}

此处我们需要使用适配器模式对其进行扩展,对UserService进行适配扩展,在不修改原有代码的基础上,适配第三方账号授权登录,复用UserServiceregister()login()方法。

接下来我们顺着UML图来进行介绍:

1)被适配(Adaptee)角色

也被称为源角色,当前被适配的角色就是UserService类,接下来要创建的适配器类就是通过继承这个类来扩展新的功能,复用注册登录方法,实现第三方账号的授权登录。

2)适配器(Adapter)角色

适配器角色,是适配器模式的核心角色。此处它包含第三方账号授权登录的核心逻辑,并通过继承UserService的方式来复用register()login()方法:

@Component
public class Login3rdAdapter extends UserService {
// ...
}

上述代码就是开篇说的类适配器模式,它可以很轻松的转换成对象适配器模式

@Component
public class Login3rdAdapter {
@Autowired
private UserService userService;
// ...
}

通过对象关联,引入UserService就是对象适配器模式了。

PS:

此处选择 类适配器模式,也就是通过类继承方式实现适配器模式。

原因:项目开发中,@Service标注的类,尽量只提供给@Controller@Service标注的类使用,当然这并非强制性的规定。

3)目标(Target)角色

在创建完适配器角色后,接下来我们需要思考的问题就是:如何创建有关第三方账号登录的方法?是直接创建在适配器类内部吗?

此处呢,需要考虑依赖倒置原则,我们需要面向接口编程。因此,需要创建一个接口,在接口内部声明第三方账号登录相关的方法,这个接口就代表了最终的目标:支持多种类第三方账号登录的功能。

public interface Login3rdTarget {

Object loginByGitee(String... params);
Object loginByQQ(String... params);
Object loginByWechat(String... params);
// ...
}

然而目标角色只是一个接口类,它必须要被子类实现。此处子类就是适配器类Login3rdAdapter,因为适配器类才是第三方账号登录功能核心逻辑的实现方

=> 因此,适配器类Login3rdAdapter在继承UserService类的同时还需要实现Login3rdTarget接口

@Component
public class Login3rdAdapter extends UserService implements Login3rdTarget {

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

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

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

总结

写到这里,适配器类就该结束了,接下来就是实现具体的逻辑了。还有两个问题需要思考:

【问题一】Login3rdAdapter作为适配器Adapter角色,为什么要继承作为被适配Adaptee角色的UserService类?

【答】:因为要在不修改原有代码的基础上复用UserService的功能,为适配新的功能做准备,所以需要继承。

【问题二】Login3rdAdapter作为适配器Adapter角色,为什么要实现作为目标Target角色的Login3rdTarget接口?

【答】:因为要进行新功能的适配(扩展),Login3rdTarget代表了第三方账号登录的能力,所以需要继承。

=> 适配器Adapter角色,既能够支持已有功能(账号密码登录注册),也能够适配扩展功能(第三方账号授权登录),适配的扩展功能还可以复用已有的方法(register()login()方法)。