首页 > 其他分享 >设计模式:适配器模式

设计模式:适配器模式

时间:2024-02-07 16:33:05浏览次数:30  
标签:适配 适配器 模式 xhr Ajax key 设计模式

设计模式是通用的、可复用的代码设计方案,也可以说是针对某类问题的解决方案,因此,掌握好设计模式,可以帮助我们编写更健壮的代码。

wiki中将设计模式分为四类,分别是:

  • 创建模式(creational patterns)
  • 结构模式(structural patterns)
  • 行为模式(behavioral patterns)
  • 并发模式(concurrency patterns)

适配器模式属于其中的结构型模式,结构型——从名称上就可以看出——与结构有关,应用这类模式不会影响对象的行为,但是会影响代码结构。那么适配器模式究竟是怎样的一种解决方案,适合什么场景呢,接下来我们就来探究一下。

适配

首先我们来先扣个字眼,适配是什么意思呢?我直接问ChatGPT,得到了以下的回答:

"适配"在计算机领域通常指的是使软件、程序或网站能够在不同的设备、平台或环境下正常工作和显示的过程。适配的主要目的是确保用户能够在各种设备上获得一致的用户体验,而不受设备类型、屏幕尺寸、操作系统或浏览器等因素的影响。

简单粗暴一点理解就是指的兼容性。

所以应用适配器模式的目的简单来理解,就是提高兼容性。

这类生活场景非常常见,比如公司给员工配了一台显示器,但是外接屏幕自带连接线的接头与电脑已有的接口不适配,两者无法连接上,这种情况是很常见的,随着技术升级、数码设备不断的升级换代,导致市面上存在很多类型的接口,于是转接头就应运而生了——转接头就是适配器模式的一种具象应用。

编程

适配在编程中也是一个常见需求。就比如WIKI中的描述:

It is often used to make existing classes work with others without modifying their source code.

翻译过来的意思是:它(适配器模式)通常用于在不修改源代码的情况下使现有类与其他类协同工作。

很多开发小伙伴在现实工作中对这点应该都有所体会,在程序员的工作中很多时候都需要去维护已有项目,迭代新的需求,然后就可能碰到这类场景。

比如老代码中有些类或者对象的某个方法,在项目中的其他地方有调用,但是某天,突然来了一个需求,增加一个功能模块,然后这个模块需要与这些类或者对象交互,实现与这个方法类似但存在细微不同点的功能。

针对这个需求,如果不应用适配器模式,我们可以有以下两种做法:

第一种,如果这个方法调用的地方比较少,这里是说如果,那我们可以简单粗暴地直接把这个方法改了,测试环节就稍微麻烦点,在测试新功能模块的同时还需要回归测试原本调用这个方法的地方。

第二种,给对象增加一个新的方法提供给新模块调用,当然这个新方法中的很多代码会与老方法中的代码重复。

很显然,这两种做法都不够好,第一种需要回归测试,而且很容易有遗漏,甚至可能引起原因不明的bug;第二种则可能使项目中存在很多冗余代码,而且还可能影响后期维护,比如修改某段逻辑就要修改两个方法的代码,如果是其他人来接手维护,很可能根本不知道是这样的情况。

适配器模式就可以应用于这类场景,它主要帮助我们解决以下问题:

  • 代码复用
  • 让接口不兼容的类协同工作

模式描述

适配器模式描述了它是如何帮助我们解决上述问题的:

  • 定义一个单独的适配器类,将一个类(待适配)的(不兼容)接口转换成客户端需要的另一个接口(target)。
  • 通过适配器来处理(重用)不具备所需接口的类。

也就是说,应用适配器模式主要做的事情,就是在代码中增加一个适配器的角色。

前端应用

JavaScript作为一种面向对象编程语言,当然也可以应用适配器模式。我们来看下面的一个例子:

Web端在以前使用Ajax技术处理异步的时候,都是通过XHR对象,但是随着Promise的推出,出现了更简洁的fetch方法,为了更方便地处理异步,现在某负责人准备在新项目中应用fetch方法,新项目从老项目中拷贝了基础文件,其中包括了Ajax代码,为了使项目成员快速熟悉,Ajax方法最好在用法上保持一致。

假设以下是原本的Ajax代码,是基于XMLHttpRequest对象进行封装的:

function Ajax(method, url, {query, params, headers, successCallback }) {
    // 1. 创建对象
    const xhr = new XMLHttpRequest();
    // 2. 初始化 设置请求类型和url
    method = method.toUpperCase();
    let queryString = '?';
    if (query && query instanceof Object) {
        for (const key in query) {
            queryString += `${key}=${query[key]}&`
        }
        url += queryString.substring(0, queryString.length - 1);
    }
    xhr.open(method, url);
    // 3. 设置请求头
    for (const key in headers) {
        xhr.setRequestHeader(key, headers[key]);
    }
    // 4. 发送请求
    let paramString = '';
    if (params && params instanceof Object) {
        for (const key in params) {
            paramString += `${key}=${params[key]}&`
        }
        paramString = paramString.substring(0, paramString.length - 1);
    }
    xhr.send(paramString);
    // 5. 事件绑定 处理服务端返回的结果
    // on 当...的时候
    // readystate 0-初始化创建的时候 1-open的时候 2-send的时候 3-服务端部分返回的时候 4-服务端返回全部的时候
    // change 改变
    xhr.onreadystatechange = function () {
        // 判断 服务端返回了所有的结果
        if (xhr.readyState === 4) {
            // 判断响应状态码 200 404 403 401 500
            // 2xx 成功
            if (xhr.status >= 200 && xhr.status < 300) {
                let result = {
                    status: xhr.status, // 状态码
                    statusText: xhr.statusText, // 状态字符串
                    responseHeaders: xhr.getAllResponseHeaders(), // 所有响应头
                    response: xhr.response // 响应体
                }
                successCallback(result);
            }
        }
    }
}

为了使项目中熟悉XHR调用方式的成员和熟悉fetch的成员能统一调用Ajax方法,我们可以使用适配器模式来对代码进行改造。

首先创建一个适配器对象,在JavaScript中我们知道,函数也是对象,所以我们定义如下函数:

async function AjaxAdapter(method, url, {query, params, headers, successCallback }) {
  // ...
}

这个函数的入参与原本的Ajax函数保持一致。在这里声明async异步函数是因为fetch方法的返回值是Promise类型。

然后我们修改Ajax函数,去调用这个适配器函数:

async function Ajax(method, url, {query, params, headers, successCallback }) {
    return AjaxAdapter(method, url, {query, params, headers, successCallback });
}

我们在适配器函数中去处理不同的使用方式,比如如果调用者传递了successCallback这个回调函数,说明他是旧方式的使用者,那么就在适配器函数中将异步返回的结果通过successCallback进行传递,否则就不对异步结果做处理,由调用者自行处理异步函数的结果。

这样无论是XHR的使用者还是fetch的使用者,都能同样使用Ajax函数获取异步结果,而不会感知到其中的不同,XHR的使用者就不必一定要去学习fetch的使用,只要像以前一样使用Ajax函数即可。

除了功能适配,数据适配在开发中也很常见,比如设定数据规范,以便于在不同系统和应用程序之间进行数据交互和处理。

总结

通过以上的探讨我们可以发现,适配器模式在实际生活和编程中的应用其实是很普遍和广泛的,为了提高兼容性而增加适配器角色也是一个很常见的行为,适配器的主要功能就是帮助我们抹平差异,也就是在适配器的内部会去根据差异来做一些处理,而这些处理对用户来说是透明的,不需要了解的。

标签:适配,适配器,模式,xhr,Ajax,key,设计模式
From: https://www.cnblogs.com/beckyyyy/p/18011047

相关文章

  • 互联网医院|互联网医院系统创新诊疗模式
    互联网医院,看似简单却隐藏着复杂的操作。想要在线上开展合法合规的诊疗业务,并非易事。有三个关键要素不可少:一是符合当地政策要求的线下实体医疗机构;二是合法合规的互联网医院系统;三是通过申办获得的互联网医院牌照。互联网医院牌照申办费用实际上包括了线下实体医疗机构建设和互联......
  • 软件架构模式系列:0. 导航
     写在前面:春节放假,闲着无聊,发现了一本好书《Softwarearchitecturepatterns》的第二版。越看越觉得有意思,索性全部翻译出来。作者是Mark Richards,大师级人物,相信很多同学都有所耳闻。1. 如果喜欢看英文原版的同学,直接去看原版。也欢迎各位同学看完原文之后回来交流。2. ......
  • 软件架构模式之第一章:介绍
        在缺乏正式架构的情况下,开发人员开始编写应用程序是一种非常普遍的做法。这种做法通常会导致组件定义不明确,创建出被称为“大泥球”的东西。这些结构通常紧密耦合、脆弱且难以改变,并且缺乏清晰的愿景或方向。在没有定义良好的架构风格时,也很难确定应用程序具有哪些架构......
  • 软件架构模式之第二章:架构结构和风格
        架构风格允许您利用现有且广为人知的结构,以支持特定的架构特征(也称为非功能性质量属性、系统质量属性或“-ilities”)。它们不仅提供了一个定义给定系统架构起点的框架,还促进了开发人员、架构师、质量保证测试人员、运营专家甚至在某些情况下业务相关方之间的交流。 ......
  • 通达信【龙头战狼】珍藏版套装指标 止盈止损 胜者为王 终极盈利模式 源码文件分享
    {股票指标}【战狼波段主图】本套指标设计两个主图,一个看盘简单明了,还有一个波段主图,操作波段上涨非常好,买卖点明确!【战狼主力资金】副图有拉升资金和主力资金两个信号,两个信号都大于0,而且处于上升趋势,易产生大妖股,可以辅助战狼信号操盘.1、指标原理:本指标主力洗盘+拉升特征......
  • golang之设计模式
    [选项模式]packagemainimport"fmt"typeOptionFuncfunc(*DoSomethingOption)typeDoSomethingOptionstruct{aintbstringcbool}funcNewDoSomethingOption(cbool,opts...OptionFunc)*DoSomethingOption{s:=&DoSomethi......
  • 【设计模式】原型模式——其他框架源码中的原型模式
    原型模式在其他框架源码中也有广泛的应用。Retrofit众所周知Retrofit是OkHttp的扩展,因此Retrofit的Call接口也像OkHttp的Call类一样实现了原型模式。Call与原型模式有关的代码如下:publicinterfaceCall<T>extendsCloneable{//……代码省略……/***Createanew,i......
  • 设计模式(Design Pattern)
    目录设计模式(DesignPattern)面向对象设计原则创建型模式结构型模式行为型模式设计模式(DesignPattern)概念与定义是一套被反复使用的、多数人知晓的、经过分类编目的代码设计经验的总结。设计模式(DesignPattern)是一种对于软件系统中不断重现的设计问题的解决方案进行......
  • 问题:深蹲动作模式,练习中双脚支撑的宽度是怎么样的?
    问题:深蹲动作模式,练习中双脚支撑的宽度是怎么样的?参考答案如图所示......
  • springboot整合redis的哨兵模式
    在SpringBoot中整合Redis的哨兵模式涉及到配置SpringBoot应用程序以连接到Redis哨兵集群。哨兵模式是Redis的一种高可用解决方案,它提供了自动故障转移功能,可以在Redis主节点发生故障时自动将一个从节点升级为新的主节点。步骤1:安装并配置Redis哨兵集群首先,您需要在您的服务器上......