当前位置:首页 > 科技  > 软件

三言两语说透设计模式的艺术-适配器模式

来源: 责编: 时间:2023-08-20 23:17:06 501观看
导读在前端开发中,我们经常会遇到不同模块、库或 API 之间的接口不兼容的情况。这可能是由于接口的变更、不同技术栈之间的差异,或是迁移项目时遗留下来的问题。为了解决这些问题,适配器模式提供了一种有效的解决方案。1、什

taE28资讯网——每日最新资讯28at.com

在前端开发中,我们经常会遇到不同模块、库或 API 之间的接口不兼容的情况。这可能是由于接口的变更、不同技术栈之间的差异,或是迁移项目时遗留下来的问题。为了解决这些问题,适配器模式提供了一种有效的解决方案。taE28资讯网——每日最新资讯28at.com

1、什么是适配器模式?

假设你在中国买了一个新的iPhone,但是充电器的接口是美国标准,不能直接插入中国的电源插座。这时候你可以使用一个电源适配器,它一端是美标插头,可以连接iPhone充电器,另一端是中国标准插头,可以插进中国的电源插座。taE28资讯网——每日最新资讯28at.com

这个电源适配器就扮演了适配器模式中的角色:taE28资讯网——每日最新资讯28at.com

  • 目标(Target)接口:中国标准电源插座
  • 适配者(Adaptee):iPhone充电器的美标接口
  • 适配器(Adapter):电源适配器,实现了目标接口,同时封装了适配者
  • 客户(Client):你和你的iPhone 通过适配器,原本不能匹配使用的美标充电器和中国电源接口可以一起工作,所以你可以给iPhone充电。

这就像在代码中使用适配器模式可以让不同的接口一起工作一样。taE28资讯网——每日最新资讯28at.com

适配器模式是一种结构性设计模式,旨在将一个类的接口转换为客户端期望的另一种接口。这使得原本因接口不兼容而无法一起工作的类可以一起协同工作。适配器模式通过创建一个中间适配器类来实现接口的转换,从而使得不同接口之间能够进行交互。taE28资讯网——每日最新资讯28at.com

2、适配器模式的结构和使用场景

适配器模式包含以下主要角色:taE28资讯网——每日最新资讯28at.com

  • 目标(Target) - 定义客户端所需的和适配器需要实现的接口
  • 适配器(Adapter) - 转换接口到目标接口的适配器
  • 适配者(Adaptee) - 需要适配的接口
  • 客户(Client) - 通过目标接口调用适配器

taE28资讯网——每日最新资讯28at.com

适配器实现了目标接口,同时封装了适配者。客户端通过目标接口调用适配器,适配器再调用适配者接口,这样就实现了接口的转换。taE28资讯网——每日最新资讯28at.com

适配器模式通常用于:taE28资讯网——每日最新资讯28at.com

  • 复用已有的类,而接口不匹配时. 通过适配器可以使得原类和接口匹配。
  • 希望复用一些现存的类,但是接口与业务要求不一致时。
  • 需要访问业务领域中的多个子系统的功能,而多个子系统具有不一致的接口时。 可以使用适配器模式构建一个统一的接口,使多个子系统功能对外以统一的接口呈现,提高子系统的透明度和复用度。

3、前端开发中使用适配器模式

适配器模式在前端开发中使用广泛,主要通过编写适配器组件来解决不同接口不兼容的问题。下面我通过几个例子来具体介绍。taE28资讯网——每日最新资讯28at.com

第三方库的接口不兼容

假设你正在使用两个不同的图表库,每个库都有自己独特的数据格式和 API。然而,你希望在一个页面上同时使用这两个库来呈现不同类型的图表。通过创建适配器,你可以将一个库的数据格式转换为另一个库所需的格式,从而实现两者的协同工作。taE28资讯网——每日最新资讯28at.com

假设我们有两个图表库,一个是名为 ChartJS 的库,另一个是名为 Highcharts 的库。每个库都有自己不同的数据格式和 API,我们希望能够在同一个项目中使用这两个库。taE28资讯网——每日最新资讯28at.com

首先,我们定义 ChartJS 和 Highcharts 两个库的接口:taE28资讯网——每日最新资讯28at.com

// ChartJS 接口interface ChartJS {    render(data: number[]): void;}// Highcharts 接口interface Highcharts {    draw(data: number[]): void;}

然后,我们创建适配器类来适配 ChartJS 到 Highcharts:taE28资讯网——每日最新资讯28at.com

// ChartJS 到 Highcharts 的适配器class ChartJSAdapter implements Highcharts {    private chartJS: ChartJS;    constructor(chartJS: ChartJS) {        this.chartJS = chartJS;    }    draw(data: number[]): void {        // 将 ChartJS 的 render 方法适配成 Highcharts 的 draw 方法        this.chartJS.render(data);    }}

最后,我们可以在客户端代码中使用适配器来实现图表的绘制:taE28资讯网——每日最新资讯28at.com

// 使用适配器创建 Highcharts 实例const chartJSInstance: ChartJS = {    render: (data: number[]) => {        console.log(`ChartJS rendering: ${data}`);    }};const chartAdapter = new ChartJSAdapter(chartJSInstance);// 绘制图表const data = [10, 20, 30, 40, 50];chartAdapter.draw(data);

在这个示例中,我们创建了一个适配器类 ChartJSAdapter,它实现了 Highcharts 接口,但在内部使用了 ChartJS 实例。适配器的 draw 方法将 ChartJS 的 render 方法适配成了 Highcharts 的 draw 方法,从而使得我们可以在不同的库之间进行适配。taE28资讯网——每日最新资讯28at.com

不同平台之间的兼容性

在不同浏览器平台可能具有不同的界面和 API 要求,通过创建适配器可以用来抹平这些差异,你可以根据目标平台的需求适配相应的界面元素和功能,从而实现代码的重用和跨平台开发。taE28资讯网——每日最新资讯28at.com

例如,我们需要编程式获取页面滚动位置:taE28资讯网——每日最新资讯28at.com

interface ScrollPositionReader {  getScrollPosition(): {x: number, y: number}; }

而不同浏览器有不同的获取滚动位置方法:taE28资讯网——每日最新资讯28at.com

// Chrome, Firefox等window.scrollXwindow.scrollY// IE8及以下document.body.scrollLeftdocument.body.scrollTop

为了统一接口,我们可以编写适配器:taE28资讯网——每日最新资讯28at.com

class ScrollPositionAdapter implements ScrollPositionReader {  getScrollPosition() {    if (window.scrollX != null) {      return {        x: window.scrollX,        y: window.scrollY        }    } else {      return {        x: document.body.scrollLeft,        y: document.body.scrollTop      }    }  }}

然后就可以通过统一的ScrollPositionReader接口获取滚动位置了:taE28资讯网——每日最新资讯28at.com

const positionReader = new ScrollPositionAdapter();const pos = positionReader.getScrollPosition();

这样,适配器帮我们解决了不同浏览器接口的不兼容问题。在前端工程化配置中,babel和ployfill也使用了适配器模式,将代码进行编译,来实现对不同浏览器版本的兼容。taE28资讯网——每日最新资讯28at.com

适配后端接口变更

当后端 API 发生变更时,前端可能需要进行大量修改以适应新的数据结构和字段。通过创建适配器,你可以将新的 API 响应转换为前端旧代码所期望的数据格式,从而避免全面修改现有代码。taE28资讯网——每日最新资讯28at.com

假设我们的应用中使用了一个名为 OldAPI 的旧版 API,但由于后端的变更,API 的响应数据格式发生了改变。我们希望在不改变现有代码的情况下,适应新的数据格式。taE28资讯网——每日最新资讯28at.com

首先,我们定义 OldAPI 的旧版和新版接口:taE28资讯网——每日最新资讯28at.com

// 旧版 OldAPI 接口interface OldAPI {    requestData(): string;}// 新版 OldAPI 接口interface NewAPI {    requestNewData(): string;}

然后,我们创建适配器类来适配旧版 OldAPI 到新版 NewAPI:taE28资讯网——每日最新资讯28at.com

// 适配旧版 OldAPI 到新版 NewAPI 的适配器class OldAPIToNewAdapter implements NewAPI {    private oldAPI: OldAPI;    constructor(oldAPI: OldAPI) {        this.oldAPI = oldAPI;    }    requestNewData(): string {        const oldData = this.oldAPI.requestData();        // 对旧数据进行适配转换        const newData = `${oldData} (adapted)`;        return newData;    }}

最后,我们可以在客户端代码中使用适配器来请求新版数据:taE28资讯网——每日最新资讯28at.com

// 使用适配器创建 NewAPI 实例const oldAPIInstance: OldAPI = {    requestData: () => {        return "Old data";    }};const apiAdapter = new OldAPIToNewAdapter(oldAPIInstance);// 请求新版数据const newData = apiAdapter.requestNewData();console.log(newData);

在这个示例中,我们创建了一个适配器类 OldAPIToNewAdapter,它实现了新版 NewAPI 接口,但在内部使用了旧版 OldAPI 实例。适配器的 requestNewData 方法将旧版 API 的响应数据进行了适配转换,使得旧版 API 的响应能够适应新版接口的需求。taE28资讯网——每日最新资讯28at.com

用适配器进行Mock模拟

当涉及使用适配器来进行 Mock 模拟时,我们可以考虑一个场景:一个应用需要从后端获取用户信息,但是在开发阶段,后端可能还没有完全实现,或者我们希望在测试中使用模拟的数据。我们可以使用适配器来模拟后端 API,以便在开发和测试中使用。taE28资讯网——每日最新资讯28at.com

首先,我们定义一个用户信息的接口,用于后端 API 和适配器的标准:taE28资讯网——每日最新资讯28at.com

interface UserInfo {    id: number;    name: string;    email: string;}

然后,我们创建一个后端 API 接口,模拟后端实际返回的数据:taE28资讯网——每日最新资讯28at.com

interface BackendAPI {    getUserInfo(userId: number): UserInfo;}

接下来,我们可以创建一个适配器来模拟后端 API,以便在开发和测试中使用:taE28资讯网——每日最新资讯28at.com

class MockBackendAdapter implements BackendAPI {    getUserInfo(userId: number): UserInfo {        // 模拟返回用户信息        return {            id: userId,            name: "Mock User",            email: "mock@example.com"        };    }}

最后,我们可以在应用中使用适配器来获取用户信息:taE28资讯网——每日最新资讯28at.com

function getAppUserInfo(api: BackendAPI, userId: number): UserInfo {    return api.getUserInfo(userId);}// 在开发阶段使用模拟的后端适配器const mockBackend = new MockBackendAdapter();const userInfo = getAppUserInfo(mockBackend, 123);console.log(userInfo);

在这个示例中,我们使用适配器 MockBackendAdapter 来模拟后端 API。适配器实现了 BackendAPI 接口,但在内部返回了模拟的用户信息数据。通过这种方式,我们可以在开发阶段使用模拟数据来测试应用的功能,而无需等待实际后端开发完成。taE28资讯网——每日最新资讯28at.com

4、适配器模式的优缺点

适配器模式是一个有力的设计工具,可以帮助我们处理不同接口之间的兼容性问题,提高代码的可维护性和可扩展性。然而,开发者需要在使用适配器时谨慎权衡其优缺点,确保在特定情况下它能够真正带来价值。以下是适配器模式的优缺点。taE28资讯网——每日最新资讯28at.com

(1)优点

  • 解耦代码: 适配器模式可以帮助解耦不同模块之间的依赖关系,使它们能够独立演化和维护。这有助于降低代码的耦合度,提高代码的可维护性和可扩展性。
  • 重用既有代码: 适配器模式允许我们在不修改现有代码的情况下,适应新的接口或需求。这使得我们能够重用既有的代码,减少重复劳动和开发成本。
  • 平滑迁移: 当项目需要进行迁移或升级时,适配器模式可以帮助我们平滑过渡。通过创建适配器,我们可以将旧的接口适配成新的接口,从而避免全面修改现有代码。
  • 灵活性和扩展性: 适配器模式可以为系统引入一层灵活的中间层,从而使得系统更具有扩展性。新的适配器可以轻松添加,以适应未来可能出现的变化。

(2)缺点:

  • 引入复杂性: 使用适配器模式可能会引入一些额外的类和层级,增加代码的复杂性。开发者需要仔细权衡是否值得引入适配器来解决接口兼容性问题。
  • 运行时开销: 在运行时执行适配转换可能会引入一些运行时开销,特别是在大规模数据转换时。这可能会对应用的性能产生影响。
  • 设计合理性: 使用适配器模式时,需要确保适配器的设计合理性,以确保适配器类的职责清晰,并且不会引入额外的复杂性。

5、总结

适配器模式是前端开发中的一个重要设计模式,可以帮助我们解决不同接口之间的兼容性问题。通过创建适配器类,我们可以将不兼容的接口转换为可互操作的形式,实现模块之间的协同工作。taE28资讯网——每日最新资讯28at.com

在 TypeScript 中,适配器模式可以通过创建中间适配器类来实现,从而实现代码的解耦和重用。taE28资讯网——每日最新资讯28at.com

在实际开发中,适配器模式常用于处理第三方库的接口兼容性问题、应对 API 的变更以及实现跨平台开发。然而,开发者需要在使用适配器模式时权衡其优缺点,确保其对项目的长期维护和可扩展性没有负面影响。taE28资讯网——每日最新资讯28at.com

通过合理的设计和实践,适配器模式将成为前端开发中的有力工具,帮助我们更好地管理和整合不同模块和技术。taE28资讯网——每日最新资讯28at.com

本文链接:http://www.28at.com/showinfo-26-6176-0.html三言两语说透设计模式的艺术-适配器模式

声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com

上一篇: 揭穿DevOps的5个谣言!

下一篇: 解锁TypeScript的潜力:改进标准库类型

标签:
  • 热门焦点
Top