Maison >interface Web >js tutoriel >Application d'adaptateurs en JavaScript (avec exemples)

Application d'adaptateurs en JavaScript (avec exemples)

不言
不言original
2018-09-19 15:08:401602parcourir

Le contenu de cet article concerne l'application d'adaptateurs en JavaScript (avec des exemples). Il a une certaine valeur de référence. Les amis dans le besoin peuvent s'y référer.

Le modèle de conception de l'adaptateur est très utile en JavaScript. Il peut être vu dans la gestion des problèmes de compatibilité entre navigateurs et dans l'intégration des appels de plusieurs SDK tiers.
En fait, dans le développement quotidien, nous écrivons souvent par inadvertance du code conforme à un certain modèle de conception. Après tout, les modèles de conception sont des modèles résumés et affinés par les seniors qui peuvent aider à améliorer l'efficacité du développement. .
En fait, les adaptateurs devraient être relativement courants en JavaScript.

Dans Wikipédia, la définition du modèle d'adaptateur est :

En génie logiciel, le modèle d'adaptateur est un modèle de conception logicielle qui permet d'utiliser l'interface d'une classe existante à partir d'une autre interface. Il est souvent utilisé pour faire fonctionner des classes existantes avec d’autres classes sans modifier leur code source.

Exemples tirés de la vie

La chose la plus courante dans la vie est l'adaptateur de prise de courant. Les normes de prise de courant des différents pays du monde sont différentes si vous devez acheter la prise de courant correspondante. les normes de chaque pays, ce serait alors un gaspillage d'argent excessif. Il serait certainement irréaliste d'apporter la prise, de briser les murs des maisons des autres et de les recâbler.
Il y aura donc un adaptateur de prise, qui sert à convertir un type de prise en un autre type de prise. Cette chose qui fait office de transfert entre la prise et votre alimentation est l'adaptateur.

Application dadaptateurs en JavaScript (avec exemples)

se reflète dans le code

et en ce qui concerne la programmation, voici ma compréhension personnelle :

Convertissez ceux si vous cachez le code sale que vous ne voulez pas voir, vous pouvez dire que c'est un adaptateur

Connectez-vous à plusieurs SDK tiers

À titre d'exemple dans le développement quotidien, nous développons un compte public WeChat, WeChat's Le module de paiement y est utilisé. Après une longue période de débogage conjoint, l'ensemble du processus a enfin été exécuté. Juste au moment où vous êtes prêt à emballer et à lancer le code avec plaisir, vous obtenez une nouvelle exigence :
Nous. besoin d'y accéder. Le SDK du compte officiel Alipay doit également avoir un processus de paiement

Afin de réutiliser le code, nous pouvons écrire cette logique dans le script :

if (platform === 'wechat') {
  wx.pay(config)
} else if (platform === 'alipay') {
  alipay.pay(config)
}

// 做一些后续的逻辑处理

Mais en général, on dit que les méthodes d'appel d'interface fournies par les SDK des différents fabricants sont quelque peu différentes Bien que parfois le même document puisse être utilisé, grâce à nos amis.

Le code ci-dessus peut donc ressembler à ceci :

// 并不是真实的参数配置,仅仅举例使用
const config = {
  price: 10,
  goodsId: 1
}

// 还有可能返回值的处理方式也不相同
if (platform === 'wechat') {
  config.appId = 'XXX'
  config.secretKey = 'XXX'
  wx.pay(config).then((err, data) => {
    if (err) // error

    // success
  })
} else if (platform === 'alipay') {
  config.token = 'XXX'
  alipay.pay(config, data => {
    // success
  }, err => {
    // error
  })
}

Pour l'instant, l'interface du code est assez claire. Tant qu'on écrit bien les commentaires, ce n'est pas trop. beaucoup. Mauvais code.
Mais la vie est toujours pleine de surprises, et nous avons reçu des demandes pour ajouter le SDK de QQ, le SDK de Meituan, le SDK de Xiaomi ou le SDK de certaines banques.

À ce stade, votre code peut ressembler à ceci :

switch (platform) {
  case 'wechat':
    // 微信的处理逻辑
  break
  case 'QQ':
    // QQ的处理逻辑
  break
  case 'alipay':
    // 支付宝的处理逻辑
  break
  case 'meituan':
    // 美团的处理逻辑
  break
  case 'xiaomi':
    // 小米的处理逻辑
  break
}

Ce n'est plus un problème que certains commentaires peuvent compenser. Un tel code deviendra de plus en plus difficile à maintenir, et divers. Le SDK a toutes sortes de méthodes d'appel étranges. Si d'autres ont des besoins similaires et doivent réécrire un tel code, ce sera certainement un gaspillage de ressources.

Ainsi, afin d'assurer la clarté de notre logique métier, et d'éviter que les générations futures ne tombent sur cet écueil à plusieurs reprises, nous allons la scinder et exister en tant que fonction publique :
Trouver l'un d'entre eux La vocation La méthode du SDK ou une règle sur laquelle nous nous sommes mis d’accord est utilisée comme référence.
Disons à l'appelant ce que vous voulez faire, comment vous pouvez obtenir les données de retour, puis nous effectuons ces divers jugements sales à l'intérieur de la fonction :

function pay ({
  price,
  goodsId
}) {
  return new Promise((resolve, reject) => {
    const config = {}

    switch (platform) {
      case 'wechat':
        // 微信的处理逻辑
        config.price = price
        config.goodsId = goodsId
        config.appId = 'XXX'
        config.secretKey = 'XXX'
        wx.pay(config).then((err, data) => {
          if (err) return reject(err)

          resolve(data)
        })
      break
      case 'QQ':
        // QQ的处理逻辑
        config.price = price * 100
        config.gid = goodsId
        config.appId = 'XXX'
        config.secretKey = 'XXX'
        config.success = resolve
        config.error = reject
        qq.pay(config)
      break
      case 'alipay':
        // 支付宝的处理逻辑
        config.payment = price
        config.id = goodsId
        config.token = 'XXX'
        alipay.pay(config, resolve, reject)
      break
    }
  })
}

De cette façon, peu importe où nous sont un environnement, tant que notre adaptateur le prend en charge, nous pouvons l'appeler selon les règles générales sur lesquelles nous nous sommes mis d'accord. Le SDK spécifique qui est exécuté est quelque chose dont l'adaptateur doit se soucier :

// run anywhere
await pay({
  price: 10,
  goodsId: 1
})

Pour le fournisseur de SDK , il vous suffit de connaître certains paramètres dont vous avez besoin, puis de renvoyer les données à votre manière.
Pour la salle d'appel du SDK, nous n'avons besoin que des paramètres communs sur lesquels nous nous sommes mis d'accord, et le traitement des rappels de surveillance est effectué de la manière convenue.

La tâche d'intégrer plusieurs SDK tiers est laissée à l'adaptateur. Ensuite, nous compressons, obscurcissons et mettons le code de l'adaptateur dans un coin invisible. Une telle logique de code deviendra très compliquée :).

C'est à peu près le rôle des adaptateurs. Une chose doit être claire. Les adaptateurs ne sont pas une solution miracle __Ces codes encombrants existeront toujours, mais vous ne pouvez pas les voir lorsque vous écrivez des affaires __, hors de vue. , hors de l'esprit.

Quelques autres exemples

Personnellement, je pense qu'il existe de nombreux exemples d'adaptateurs dans jQuery, y compris le plus basique $('selector').on N'est-ce pas un modèle d'adaptateur évident ?

Rétrogradez étape par étape et atténuez certaines différences entre les navigateurs, ce qui nous permet d'utiliser un on simple pour surveiller les événements dans les navigateurs grand public :

// 一个简单的伪代码示例
function on (target, event, callback) {
  if (target.addEventListener) {
    // 标准的监听事件方式
    target.addEventListener(event, callback)
  } else if (target.attachEvent) {
    // IE低版本的监听方式
    target.attachEvent(event, callback)
  } else {
    // 一些低版本的浏览器监听事件方式
    target[`on${event}`] = callback
  }
}

或者在Node中的这样的例子更是常见,因为早年是没有Promise的,所以大多数的异步由callback来完成,且有一个约定好的规则,Error-first callback

const fs = require('fs')

fs.readFile('test.txt', (err, data) => {
  if (err) // 处理异常

  // 处理正确结果
})

而我们的新功能都采用了async/await的方式来进行,当我们需要复用一些老项目中的功能时,直接去修改老项目的代码肯定是不可行的。  
这样的兼容处理需要调用方来做,所以为了让逻辑代码看起来不是太混乱,我们可能会将这样的回调转换为Promise的版本方便我们进行调用:

const fs = require('fs')

function readFile (fileName) {
  return new Promise((resolve, reject) => {
    fs.readFile(fileName, (err, data) => {
      if (err) reject(err)

      resolve(data)
    })
  })
}

await readFile('test.txt')

因为前边也提到了,这种Error-first callback是一个约定好的形式,所以我们可以很轻松的实现一个通用的适配器:

function promisify(func) {
  return (...args) => new Promise((resolve, reject) => {
    func(...args, (err, data) => {
      if (err) reject(err)

      resolve(data)
    })
  })
}

然后在使用前进行对应的转换就可以用我们预期的方式来执行代码:

const fs = require('fs')

const readFile = promisify(fs.readFile)

await readFile('test.txt')
在Node8中,官方已经实现了类似这样的工具函数:util.promisify

小结

个人观点:所有的设计模式都不是凭空想象出来的,肯定是在开发的过程中,总结提炼出的一些高效的方法,这也就意味着,可能你并不需要在刚开始的时候就去生啃这些各种命名高大上的设计模式。  
因为书中所说的场景可能并不全面,也可能针对某些语言,会存在更好的解决办法,所以生搬硬套可能并不会写出有灵魂的代码 :)

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn