ホームページ  >  記事  >  ウェブフロントエンド  >  JavaScript でのアダプターのアプリケーション (例付き)

JavaScript でのアダプターのアプリケーション (例付き)

不言
不言オリジナル
2018-09-19 15:08:401550ブラウズ

この記事は JavaScript でのアダプターの適用に関するものです (サンプル付き)。必要な方は参考にしていただければ幸いです。

アダプター設計パターンは、ブラウザー間の互換性の問題に対処したり、複数のサードパーティ SDK からの呼び出しを統合したりする場合に、JavaScript で非常に役立ちます。
実際、私たちは日々の開発において、うっかり特定のデザインパターンに準拠したコードを書いてしまうことがよくあります。結局のところ、デザインパターンは、開発効率を向上させるために上級者によってまとめられ、改良されたテンプレートです。 。
このアダプターは、実際には JavaScript で比較的一般的なものでなければなりません。

Wikipedia では、アダプター パターンの定義は次のとおりです。

ソフトウェア エンジニアリングでは、アダプター パターンは、既存のクラスのインターフェイスを別のインターフェイスから使用できるようにするソフトウェア設計パターンです。これは、ソース コードを変更せずに、既存のクラスを他のクラスと連携させるためによく使用されます。

生活での例

生活で最も一般的なものは、世界各国のコンセント規格が異なるため、それに応じて対応する電源プラグを購入する必要があります。各国の規格を考慮した上で、コンセントを持ってきて他人の家の壁を壊して配線し直すなんて、あまりにもお金の無駄です。
つまり、あるタイプのプラグを別のタイプのプラグに変換するために使用されるプラグ アダプタが存在します。これは、ソケットと電源の間の転送に使用されます。

JavaScript でのアダプターのアプリケーション (例付き)

コードに反映されています

しかし、プログラミングに関しては、私は個人的に次のように理解しています。見たくない汚れたコードを非表示にすると、これはアダプターであると言えます

複数のサードパーティ SDK に接続

日常の開発の例として、私たちはWeChat パブリック アカウントでは、WeChat の支払いモジュールが使用されています。長い期間にわたる共同デバッグの後、ようやくプロセス全体が完了し、コードを無事にパッケージ化して起動する準備が整ったところで、次のような新しい要件が得られます。

#Alipay 公式アカウントの SDK にアクセスする必要があります。支払いプロセスも必要です。
コードを再利用するには、スクリプトに次のようなロジックを記述する必要があります:

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

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

ただし、一般的に、各メーカーの SDK が提供するインターフェース呼び出しメソッドは多少異なります。

同じドキュメントが使用される場合もありますが、友人のおかげです。

したがって、上記のコードは次のようになります。

// 并不是真实的参数配置,仅仅举例使用
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
  })
}

今のところ、コードのインターフェイスは、適切なコメントを記述している限り、それほど悪いコードではありません。 。

しかし、人生は常に驚きに満ちており、QQ の SDK、Meituan の SDK、Xiaomi の SDK、または一部の銀行の SDK を追加するリクエストを受けています。


現時点で、コードは次のようになります。

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

これは、コメントによって補える問題ではなくなり、このようなコードの保守はますます困難になります。 SDK にはメソッドを呼び出す機能がたくさんあり、他の人が同様のニーズを持っていてそのようなコードを書き直す必要がある場合、それは間違いなくリソースの無駄になります。

したがって、ビジネス ロジックの明確性を確保し、将来の世代がこの落とし穴を繰り返し踏むことを避けるために、私たちはそれを分割し、公的機能として存在します。

そのうちの 1 つを見つけるSDKのメソッドまたは当社が合意したルールがベンチマークとして使用されます。

呼び出し元に何をしたいのか、戻りデータをどのように取得できるのかを伝えてから、関数内でさまざまな汚い判断を行います。

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
    }
  })
}

このようにして、どのような環境であっても、では、アダプターがサポートしている限り、合意した一般ルールに従って呼び出すことができます。具体的にどの SDK が実行されるかは、アダプターが考慮する必要があるものです。
// run anywhere
await pay({
  price: 10,
  goodsId: 1
})

SDK プロバイダーの場合必要なパラメータをいくつか知っていれば、独自の方法でデータを返すことができます。

SDK コール ルームの場合、合意された共通パラメータと、合意された方法でのモニタリング コールバック処理のみが必要です。


複数のサードパーティ SDK を統合するタスクはアダプターに任せられます。その後、アダプター コードを圧縮して難読化し、そのようなコード ロジックは非常に複雑になります。

これがアダプターの役割です。1 つ明確にしておきたいのは、これらの面倒なコードは常に存在するということです。__,目に見えないところにあります。心。

その他の例

個人的には、

jQuery

には最も基本的な $('selector').on を含む多くのアダプターの例があると感じています。 、これは明らかなアダプター パターンではありませんか? 段階的にダウングレードし、ブラウザ間の差異を解消することで、シンプルな

on

: を通じて、主流のブラウザでイベント監視を実行できるようになります。<pre class="brush:php;toolbar:false">// 一个简单的伪代码示例 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   } }</pre> <p>或者在Node中的这样的例子更是常见,因为早年是没有<code>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

小结

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

以上がJavaScript でのアダプターのアプリケーション (例付き)の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事の内容はネチズンが自主的に寄稿したものであり、著作権は原著者に帰属します。このサイトは、それに相当する法的責任を負いません。盗作または侵害の疑いのあるコンテンツを見つけた場合は、admin@php.cn までご連絡ください。