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

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

总结

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

相关推荐
brzhang1 分钟前
代码即图表:dbdiagram.io让数据库建模变得简单高效
前端·后端·架构
Jamesvalley6 分钟前
【Django】新增字段后兼容旧接口 This field is required
后端·python·django
triticale10 分钟前
【蓝桥杯】P12165 [蓝桥杯 2025 省 C/Java A] 最短距离
java·蓝桥杯
Felven10 分钟前
A. Ideal Generator
java·数据结构·算法
秋野酱18 分钟前
基于 Spring Boot 的银行柜台管理系统设计与实现(源码+文档+部署讲解)
java·spring boot·后端
懒懒小徐18 分钟前
大厂面试-框架篇
面试·职场和发展
JAVA学习通32 分钟前
JAVA多线程(8.0)
java·开发语言
不当菜虚困35 分钟前
JAVA设计模式——(七)代理模式
java·设计模式·代理模式
wayhome在哪38 分钟前
大厂必考之大文件上传
面试
天天扭码41 分钟前
从数组到对象:JavaScript 遍历语法全解析(ES5 到 ES6 + 超详细指南)
前端·javascript·面试