天天看點

前端的設計模式系列-擴充卡模式場景擴充卡模式代碼實作更多場景易混設計模式總

代碼也寫了幾年了,設計模式處于看了忘,忘了看的狀态,最近對設計模式有了點感覺,索性就再學習總結下吧。

大部分講設計模式的文章都是使用的

Java

C++

這樣的以類為基礎的靜态類型語言,作為前端開發者,

js

這門基于原型的動态語言,函數成為了一等公民,在實作一些設計模式上稍顯不同,甚至簡單到不像使用了設計模式,有時候也會産生些困惑。

下面按照「場景」-「設計模式定義」- 「代碼實作」- 「更多場景」-「總」的順序來總結一下,如有不當之處,歡迎交流讨論。

場景

當我們使用第三方庫的時候,常常會遇到目前接口和第三方接口不比對的情況,比如使用一個

Table

的元件,它要求我們傳回的表格資料格式如下:

{
  code: 0, // 業務 code
  msg: '', // 出錯時候的提示
  data: {
     total: , // 總數量
     list: [], // 表格清單
  }
};
           

複制

但後端傳回的資料可能是這樣的:

{
  code: 0, // 業務 code
  message: '', // 出錯時候的提示
  data: {
     total: , // 總數量
     records: [], // 表格清單
  }
};
           

複制

此時就可以通過擴充卡模式進行轉換。

擴充卡模式

看一下 維基百科 給的定義:

★In software engineering, the adapter pattern is a software design pattern that allows the interface of an existing class to be used as another interface.[1] It is often used to make existing classes work with others without modifying their source code.

通過擴充卡模式可以讓目前

class

不改變的情況下正常使用另一個

class

在以

class

為基礎的語言中有兩種實作方式,一種是通過組合的方式,擴充卡類内部包含原對象的執行個體。一種是通過類繼承,擴充卡類繼承原

class

。可以看下

UML

類圖:

前端的設計模式系列-擴充卡模式場景擴充卡模式代碼實作更多場景易混設計模式總

image-20220213124112500

左邊的

Adapter

内部擁有

Adaptee

的執行個體,右邊的

Adapter

類直接繼承

Adaptee

類。

擴充卡會将

Adaptee

specificOperation

方法進行相應的處理包裝為

operation

方法供

client

使用。

看一個簡單的例子,現實生活中

iPhone

有兩種耳機插口,一種是

Lightning

,一種是傳統的

3.5

毫米接口。如果是

lightning

插口的耳機想要插到傳統的

3.5

毫米接口的電腦上就需要擴充卡了。

class Lightning耳機 {
 public void 插入Lighting接口(){
  System.out.println("插入到Lighting耳機接口成功");
 }
}
class 傳統耳機 {
 public void 插入到傳統耳機孔(){
  System.out.println("插入到傳統耳機孔成功");
 }
}
class Lightning耳機到傳統耳機擴充卡 extends 傳統耳機 {
 public Lightning耳機 Lightning耳機;
 public Lightning耳機到傳統耳機擴充卡(Lightning耳機 耳機) {
  Lightning耳機 = 耳機;
 }
 public void 插入到傳統耳機孔(){
  Lightning耳機.插入Lighting接口();
 }
}
class 電腦傳統耳機孔 {
 public 傳統耳機 耳機;
 public 電腦傳統耳機孔(傳統耳機 傳統耳機) {
  耳機 = 傳統耳機;
 }
 public void 插入耳機() {
  耳機.插入到傳統耳機孔();
 }
}
public class Main {
 public static void main(String[] args) {
  傳統耳機 傳統耳機 = new 傳統耳機();
  電腦傳統耳機孔  電腦傳統耳機孔 = new 電腦傳統耳機孔(傳統耳機);
  電腦傳統耳機孔.插入耳機(); // 插入到傳統耳機孔成功


  Lightning耳機 Lightning耳機 = new Lightning耳機();
  電腦傳統耳機孔  電腦傳統耳機孔2 = new 電腦傳統耳機孔(new Lightning耳機到傳統耳機擴充卡(Lightning耳機)); 
  電腦傳統耳機孔2.插入耳機(); // 插入到Lighting耳機接口成功
 }
}
           

複制

通過擴充卡我們成功将

Lightning

耳機插入到了電腦傳統耳機孔,讓我們再用

js

改寫一下。

const Lightning耳機 = {
    插入Lighting接口(){
  console.log("插入到Lighting耳機接口成功");
 }
}

const 傳統耳機 = {
    插入到傳統耳機孔(){
  console.log("插入到傳統耳機孔成功");
 }
}

const 電腦傳統耳機孔 = {
    插入耳機(耳機) {
        耳機.插入到傳統耳機孔();
    }
}

const Lightning耳機到傳統耳機擴充卡 = function(Lightning耳機) {
    return {
        插入到傳統耳機孔(){
            Lightning耳機.插入Lighting接口()
        }
    }
}

電腦傳統耳機孔.插入耳機(傳統耳機) // 插入到傳統耳機孔成功
電腦傳統耳機孔.插入耳機(Lightning耳機到傳統耳機擴充卡(Lightning耳機)) // 插入到Lighting耳機接口成功
           

複制

代碼實作

回到開頭接口不比對的問題上,

Table

元件提供了一個

responseProcessor

的鈎子,我們隻需要通過這個鈎子将接口傳回的資料進行包裝即可。

{
  ...
  responseProcessor(res) {
    return {
      ...res,
      msg: res.message, // 出錯時候的提示
      data: {
         ...res.data
         list: res?.data?.records || [], // 表格清單
      }
    };
  },
  ...
  
}
           

複制

更多場景

除了應對資料格式不一緻的問題,通過擴充卡模式我們還可以為上層提供統一接口,來解決相容性問題。最典型的例子就是

jQuery

,可以看一下其中一段代碼:

// Create the request object
// (This is still attached to ajaxSettings for backward compatibility)
jQuery.ajaxSettings.xhr = window.ActiveXObject !== undefined ?

 // Support: IE6-IE8
 function() {

  // XHR cannot access local files, always use ActiveX for that case
  if ( this.isLocal ) {
   return createActiveXHR();
  }

  // Support: IE 9-11
  // IE seems to error on cross-domain PATCH requests when ActiveX XHR
  // is used. In IE 9+ always use the native XHR.
  // Note: this condition won't catch Edge as it doesn't define
  // document.documentMode but it also doesn't support ActiveX so it won't
  // reach this code.
  if ( document.documentMode > 8 ) {
   return createStandardXHR();
  }

  // Support: IE<9
  // oldIE XHR does not support non-RFC2616 methods (#13240)
  // See http://msdn.microsoft.com/en-us/library/ie/ms536648(v=vs.85).aspx
  // and http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html#sec9
  // Although this check for six methods instead of eight
  // since IE also does not support "trace" and "connect"
  return /^(get|post|head|put|delete|options)$/i.test( this.type ) &&
   createStandardXHR() || createActiveXHR();
 } :

 // For all other browsers, use the standard XMLHttpRequest object
 createStandardXHR;
           

複制

易混設計模式

擴充卡模式和代理模式在代碼結構上很像,代理模式也是對原對象進行包裝處理。差別在于它們的意圖不同:

  • 擴充卡模式是為了解決兩個對象之間不比對的問題,而原對象又不适合直接修改,此時可以使用擴充卡模式進行一層轉換。
  • 代理模式是為了增強原對象的功能,提供的接口不會改變。

擴充卡模式是一種比較簡單的設計模式,在

js

中也會很自然的應用,一般通過一個函數進行轉換即可。