发布于 2026-01-06 3 阅读
0

如何使用优秀的适配器模式以及为什么要使用它

如何使用优秀的适配器模式以及为什么要使用它

适配器模式被归类为一种结构模式,它允许一段代码与另一段不直接兼容的代码进行通信。

首先,为了方便接下来的讨论,我们先将讨论范围限定在我们负责的 Web 应用程序的范围内。该应用程序是一个经典的三层架构:前端客户端、用于 API 的 Web 服务器以及数据存储层。这在如今是一种相当传统的技术栈。

现在我想强调一下:数据存储的地方。这可以是像 SQL Server 或 MongoDB 这样的数据库,也可以是我们用来存放数据的地方,比如 AWS S3,甚至是我们的硬盘。

理想情况下,我们的应用程序甚至无需关心数据存储或读取的位置。如果我们为这些操作定义一个通用接口,就可以在不更改应用程序本身的情况下更改数据存储或读取的位置。为此,我们可以利用仓储模式

适配器模式是一种可以在代码仓库中使用的模式。它允许应用程序代码利用一致的接口与另一段代码交互,而无需依赖于该代码本身。更直白地说,在本文中,我们将适配器定义为连接两段不相干代码的通用接口。

到目前为止你都明白了吗?如果不明白也没关系,我们来看看什么时候会用到它,以便更好地理解。

发现(潜在的)适配器模式需求

坦白说,发现适配器模式的潜在用途有时比听起来要难。这通常是因为大多数现代编程语言已经内置了适配器。但假设我们有一个IPerson如下所示的接口。

public interface Person : IPerson
{
    public string Name { get; set; }
    public string City { get; set; }
    public string IdNumber { get; set; }
}
Enter fullscreen mode Exit fullscreen mode

然后,我们有一段旧代码,它一直负责加载Person对象。

public class PersonLoader: IPersonLoader
{
    public Person LoadPerson()
    {
        //code to load a person
    }
}
Enter fullscreen mode Exit fullscreen mode

请注意,这里PersonLoader实现了一个通用接口IPersonLoader,该接口定义了名为的方法的必要性LoadPerson()。让我们看一下使用该方法的代码PersonLoader

public class LoadPeople
{
    static void Main(string[] args)
    {
        IPersonLoader loader = new PersonLoader();
        var person = loader.LoadPerson();
    }
}
Enter fullscreen mode Exit fullscreen mode

这里的加载器类型为 `<Loader>` IPersonLoader,并且PersonLoader恰好实现了该接口。因此PersonLoader,创建了一个 `<Loader>`,然后代码就可以调用 `<Loader> LoadPerson()`。到目前为止一切顺利,对吧?

但请记住,PersonLoader这是一段糟糕的代码,我们希望在不破坏整个应用程序的前提下,将其替换掉。具体来说,我们希望IPerson使用一种新的、改进的加载器来加载对象。

这里我们看到的是一个适配器模式的绝佳应用案例。

加入适配器香料

首先,我们定义了新的改进型人员加载器,BetterPersonLoader它实现了IBetterPersonLoader一个包含新方法的接口RunGetPerson()

public class BetterPersonLoader : IBetterPersonLoader
{
    public Person RunGetPerson()
    {
        //code to get person the new and improved way.
    }
}
Enter fullscreen mode Exit fullscreen mode

但我们不能直接把它接入BetterPersonLoader客户LoadPeople端。它不兼容,会破坏客户端代码,因为客户端代码需要一个IPersonLoader接口。

所以我们可以定义一个PersonAdapter实现该接口的对象。让我们看看它会是什么样子。

public class PersonAdapter : IPersonLoader
{   
    public Person LoadPerson()
    {
        var newLoader = new BetterPersonLoader();
        return newLoader.RunGetPerson();
    }
}
Enter fullscreen mode Exit fullscreen mode

然后我们可以更新LoadPeople客户端以利用我们的新适配器。

public class LoadPeople
{
    static void Main(string[] args)
    {
        IPersonLoader loader = new PersonAdapter();
        var person = loader.LoadPerson();
    }
}
Enter fullscreen mode Exit fullscreen mode

现在,这段代码能够应对未来可能再次发生的变化。如果BestPersonLoader真的发生了变化,我们只需更新PersonAdapter类,LoadPeople客户端就无需再做任何更改

public class PersonAdapter : IPersonLoader
{   
    public Person LoadPerson()
    {
        var newLoader = new BestPersonLoader();
        return newLoader.BestWayToGetPerson();
    }
}
Enter fullscreen mode Exit fullscreen mode

优点和缺点

适配器模式以多种形式出现。它可以应用于像从某个地方加载数据这样简单的场景,也可以应用于像 HTTP 客户端这样更复杂的实现中。适配器模式带来了许多好处:

  • 它提高了可重用性和灵活性。适配器的接口是预先定义并达成共识的。因此,只要遵守这一共识,我们就可以更改适配器内部的实现。
  • 客户端变得更加简洁。正如我们在示例中看到的,重构为适配器模式后,我们可以根据需要更改加载器逻辑。客户端无需做出选择,因为适配器已经约定好了IPersonLoader
  • 改变和尝试新想法,减少变动。约束被最小化到仅包含双方约定的合同,而该合同的执行则有多种解释。

这些好处固然很好,但如果我不提醒你可能会遇到的陷阱,那就太可惜了。

  • 兔子洞效应。如果对象嵌套很深,适配器的使用有时会走向极端。最终,你可能不得不AdapterA调用多个AdapterB方法AdapterC来加载一个 Person 对象。
  • 容易过度设计。请注意,在这篇文章中,我一开始的代码并没有使用适配器模式。这是因为适配器模式通常是在开发过程中自然而然出现的,并非一开始就为人所知。尽量避免在不需要的时候强行引入适配器模式。

想学习亚马逊网络服务吗?

很多人都渴望学习亚马逊云服务(AWS)。受此启发,我创建了一门课程,专注于通过实际操作来学习AWS。课程重点讲解如何托管、保护和交付静态网站。您将通过构建解决方案来学习S3、API Gateway、CloudFront、Lambda和WAF等服务。

关于AWS的信息浩如烟海,很容易迷失方向,学习过程停滞不前。通过解决这个问题,我们可以筛选信息,加快您的学习速度。我编写这本书和制作视频课程的目的,就是与您分享我的经验和心得。

听起来很有意思?访问首页了解更多信息,选择适合您的套餐,并通过实际使用学习 AWS 基础知识

文章来源:https://dev.to/kylegalbraith/how-to-use-the-excellent-adapter-pattern-and-why-you-should-2c31