适配器模式在微服务的巧妙应用

适配器模式(Adapter Pattern)是一种结构型设计模式,它允许不兼容的接口之间可以一起工作。适配器模式通常用于将一个类的接口转换成客户端期望的另一种接口,从而使原本因接口不兼容而不能一起工作的类可以一起工作。

适配器模式的介绍

适配器模式主要涉及三个角色:

  1. 目标(Target)接口:当前系统业务所期待的接口,它可以是抽象类或接口。
  2. 待适配的类(Adaptee):需要被适配的类或接口。
  3. 适配器(Adapter):通过包装一个需要被适配的对象,把原接口转换成目标接口。

适配器模式有两种实现方式:

  • 类适配器模式:通过继承来实现适配器功能。
  • 对象适配器模式:通过组合来实现适配器功能。

优缺点

优点

  1. 提高了类的复用性:系统的需求变化时,不需要修改原有的代码,只需要添加适配器即可重用现有的功能。
  2. 增加了类的透明性和灵活性:客户端代码可以透明地调用目标接口。
  3. 灵活性和扩展性都非常好:如果需要改变适配逻辑,只需更换具体的适配器即可。

缺点

  1. 过多地使用适配器会使系统凌乱。例如,明明看到调用的是A接口,实际上内部被适配成了B接口的实现。
  2. 由于Java至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是接口。

在Spring Cloud中通过Feign使用适配器模式

在Spring Cloud中,Feign是一个声明式的Web服务客户端,它使得编写Web服务客户端变得更加简单。我们可以通过Feign来调用外部接口。当外部接口的参数与我们的系统不兼容时,可以使用适配器模式来进行适配。

假设我们有一个外部微服务,它提供了一个接口,用于获取用户信息,但是这个接口的用户信息对象的结构与我们的系统中使用的用户信息对象的结构不一致。

外部服务的用户信息对象(Adaptee)

java 复制代码
public class ExternalUser {
    private String firstName;
    private String lastName;
    private String email;

    // getters and setters
}

我们系统中的用户信息对象(Target)

java 复制代码
public class InternalUser {
    private String fullName;
    private String emailAddress;

    // getters and setters
}

Feign客户端定义(Adaptee接口)

java 复制代码
@FeignClient(name = "external-user-service")
public interface ExternalUserService {
    @GetMapping("/user/{id}")
    ExternalUser getUserById(@PathVariable("id") String userId);
}

适配器(Adapter)

我们创建一个适配器,它实现我们系统中定义的接口,并在内部调用Feign客户端,将ExternalUser转换为InternalUser

java 复制代码
public class UserAdapter implements UserService {

    private final ExternalUserService externalUserService;

    public UserAdapter(ExternalUserService externalUserService) {
        this.externalUserService = externalUserService;
    }

    @Override
    public InternalUser getUserById(String userId) {
        ExternalUser externalUser = externalUserService.getUserById(userId);
        return new InternalUser(externalUser.getFirstName() + " " + externalUser.getLastName(),
                                externalUser.getEmail());
    }
}

使用适配器

现在,当我们的系统需要获取用户信息时,我们可以通过UserAdapter来获取,它会在内部调用外部服务,并将获取到的ExternalUser对象转换为我们系统中的InternalUser对象。

java 复制代码
public class UserServiceClient {

    private final UserService userService;

    public UserServiceClient(UserService userService) {
        this.userService = userService;
    }

    public InternalUser getUserById(String userId) {
        return userService.getUserById(userId);
    }
}

下面看下对象的关系:

在这个例子中,UserAdapter充当了适配器的角色,它把外部服务返回的ExternalUser对象转换为我们系统内部使用的InternalUser对象。这样,即使外部服务的接口或数据结构发生变化,我们也只需要在UserAdapter中做出相应的调整,而不需要修改系统内部的其他部分。这样不仅增加了代码的可维护性,也提高了系统的灵活性和扩展性。

总结

通过适配器方式,我们可以将不兼容的接口或数据模型转换为我们的系统可以使用的形式,同时保持系统的整洁和一致性。这样做还有助于隔离系统与外部服务的直接依赖,当外部服务变化时,只需修改适配器逻辑,而不会影响到系统的其他部分。

相关推荐
考虑考虑19 小时前
docker compose V2版本新属性
运维·后端·自动化运维
mldong19 小时前
一个 App,十三套后端:手机审批端 uni-jeeflow-app 开源了
java·架构
tqs_1234520 小时前
MySQL RR隔离级别死锁|Gap间隙锁、临键锁,订单并发范围查询死锁根因方案
java
逆境不可逃21 小时前
Pi Agent 学习笔记:多个工具怎样并行执行
java
尾善爱看海21 小时前
Vue 面试收官篇:SSR、性能优化落地、30 道高频面试题精讲(附标准答案)
前端·javascript·vue.js·面试·vue
GreenTea21 小时前
7000 万 QPS、500 PB:OpenAI 如何用一个 Python 存储平台撑住 10 亿用户
后端·架构
Flynt21 小时前
Java 27 升级实测:默认值动得比新特性多,有个老参数会让 JVM 直接起不来
java·jvm·后端
Bs_MoneyMagnet21 小时前
基于springboot+vue的个人健康管理系统的设计与实现 源码+文档
java·vue.js·spring boot·后端·vue3·springboot3·计算机毕业设计
GreenTea1 天前
OpenAI Agents API 上手实测:一次调用把整个 agent loop 甩给 OpenAI
前端·后端·算法
星云API技术支持1 天前
企业微信二次开发:群权限设置、成员管理与群资料维护的接口组合实践
java·前端·企业微信