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

适配器模式(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中做出相应的调整,而不需要修改系统内部的其他部分。这样不仅增加了代码的可维护性,也提高了系统的灵活性和扩展性。

总结

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

相关推荐
码事漫谈10 分钟前
时序数据库2026盘点:国产数据库如何以“融合多模”走出差异化之路?
前端·后端
浮游本尊15 分钟前
Java学习第42天 - Spring 事务传播、隔离级别、锁机制与并发一致性
后端
道友可好15 分钟前
让 AI 自己验收,等于让学生自己批卷
前端·人工智能·后端
wsaaaqqq28 分钟前
roudan:自由选择实体、灵活操作数据、快速写入数据库的 Java 框架
java
鱼人30 分钟前
响应式三巨头:rem / vw / em 深度对比,移动端到底该选谁?
后端
小强198834 分钟前
Grid 网格布局实战:快速实现复杂网页排版
后端
胡志辉34 分钟前
深入浅出 call、apply、bind
前端·javascript·后端
长大198834 分钟前
Flex 布局完整教程:告别浮动,拥抱万能弹性布局
后端
iccb10131 小时前
5年,一个程序员是如何把私有化在线客服系统做到第一名的
前端·后端·github
Rust研习社1 小时前
这 8 个 Rust 学习资源值得每个新手收藏起来
后端·rust·编程语言