Der Inhalt dieses Artikels befasst sich mit der Anwendung von Adaptern in JavaScript (mit Beispielen). Freunde in Not können darauf verweisen.
Das Adapterentwurfsmuster ist in JavaScript sehr nützlich. Es zeigt sich bei der Bewältigung von browserübergreifenden Kompatibilitätsproblemen und der Integration von Aufrufen mehrerer SDKs von Drittanbietern.
Tatsächlich schreiben wir in der täglichen Entwicklung oft versehentlich Code, der einem bestimmten Entwurfsmuster entspricht. Schließlich handelt es sich bei Entwurfsmustern um einige von Senioren zusammengefasste und verfeinerte Vorlagen, die zur Verbesserung der Entwicklungseffizienz beitragen können .
Tatsächlich sollten Adapter in JavaScript relativ häufig vorkommen.
In Wikipedia lautet die Definition des Adaptermusters:
In der Softwareentwicklung ist das Adaptermuster ein Software-Designmuster, das es ermöglicht, die Schnittstelle einer vorhandenen Klasse von einer anderen Schnittstelle aus zu verwenden. Es wird häufig verwendet, um vorhandene Klassen mit anderen Klassen zusammenarbeiten zu lassen, ohne deren Quellcode zu ändern.
Das häufigste Ding im Leben ist der Netzsteckeradapter. Die Steckdosenstandards verschiedener Länder auf der ganzen Welt sind unterschiedlich. Wenn Sie den entsprechenden Netzstecker kaufen müssen Dann wäre es eine zu große Geldverschwendung, die Steckdose mitzubringen, die Wände anderer Leute einzureißen und sie neu zu verkabeln.
Es wird also einen Steckeradapter geben, der dazu dient, einen Steckertyp in einen anderen Steckertyp umzuwandeln. Dieses Ding, das als Übertragung zwischen der Steckdose und Ihrer Stromversorgung dient, ist der Adapter.
und wenn ich mich der Programmierung zuwende, ist dies mein persönliches Verständnis:
Konvertieren Sie diese Wenn Sie Verstecken Sie den schmutzigen Code, den Sie nicht sehen möchten, Sie können sagen, dass es sich um einen Adapter handeltAls Beispiel für die tägliche Entwicklung entwickeln wir ein öffentliches WeChat-Konto, WeChat's Nach einer langen Zeit des gemeinsamen Debuggens ist der gesamte Prozess endlich abgeschlossen. Gerade als Sie bereit sind, den Code glücklich zu verpacken und zu starten, erhalten Sie eine neue Anforderung:
Wir Sie müssen darauf zugreifen. Das SDK des offiziellen Alipay-Kontos muss auch über einen Zahlungsprozess verfügen
Um den Code wiederzuverwenden, können wir folgende Logik in das Skript schreiben:
if (platform === 'wechat') { wx.pay(config) } else if (platform === 'alipay') { alipay.pay(config) } // 做一些后续的逻辑处理
Aber im Allgemeinen sind die von den SDKs der einzelnen Hersteller bereitgestellten Schnittstellenaufrufmethoden etwas unterschiedlich Obwohl manchmal dasselbe Dokument verwendet wird, dank unserer Freunde.
Der obige Code könnte also so aussehen:
// 并不是真实的参数配置,仅仅举例使用 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 }) }
Im Moment ist die Codeschnittstelle ziemlich klar, solange wir die Kommentare gut schreiben .
Aber das Leben ist immer voller Überraschungen und wir haben Anfragen erhalten, das SDK von QQ, das SDK von Meituan, das SDK von Xiaomi oder das SDK einiger Banken hinzuzufügen.
An diesem Punkt könnte Ihr Code so aussehen:
switch (platform) { case 'wechat': // 微信的处理逻辑 break case 'QQ': // QQ的处理逻辑 break case 'alipay': // 支付宝的处理逻辑 break case 'meituan': // 美团的处理逻辑 break case 'xiaomi': // 小米的处理逻辑 break }
Dies ist kein Problem mehr, das einige Kommentare ausgleichen können. Ein solcher Code wird immer schwieriger zu pflegen und vielfältiger SDKs sind voller seltsamer Dinge. Wenn andere Leute ähnliche Anforderungen haben und solchen Code neu schreiben müssen, ist dies definitiv eine Verschwendung von Ressourcen.
Um die Klarheit unserer Geschäftslogik zu gewährleisten und zu verhindern, dass zukünftige Generationen wiederholt in diese Falle tappen, werden wir sie aufteilen und als öffentliche Funktion existieren:
Finde eine von ihnen Die Berufung Als Benchmark dient die Methode des SDK oder eine von uns vereinbarte Regel.
Lassen Sie uns dem Anrufer sagen, was Sie tun möchten, wie Sie die Rückgabedaten erhalten können, und dann treffen wir diese verschiedenen schmutzigen Urteile innerhalb der Funktion:
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 } }) }
Auf diese Weise, egal in welcher Umgebung wir uns befinden in , sofern unser Adapter dies unterstützt, kann es gemäß den von uns vereinbarten allgemeinen Regeln aufgerufen werden. Das spezifische SDK, das ausgeführt wird, muss sich um den Adapter kümmern:
// run anywhere await pay({ price: 10, goodsId: 1 })
Für das SDK Anbieter, Sie müssen nur einige Parameter kennen, die Sie benötigen, und dann die Daten auf Ihre eigene Weise zurückgeben.
Für den SDK-Callroom benötigen wir lediglich die gemeinsamen Parameter, auf die wir uns geeinigt haben, und die Überwachung der Callback-Verarbeitung in der vereinbarten Weise.
Die Aufgabe, mehrere SDKs von Drittanbietern zu integrieren, wird dann sehr kompliziert. Dann komprimieren, verschleiern und platzieren wir den Adaptercode in einer unsichtbaren Ecke.
Das ist ungefähr die Rolle von Adaptern. Es muss klar sein, dass es diese umständlichen Codes nicht immer gibt, wenn man sie nicht sieht , verrückt.
Ich persönlich denke, dass es in jQuery
viele Adapterbeispiele gibt, einschließlich der grundlegendsten $('selector').on
. Ist das nicht ein offensichtliches Adaptermuster?
Schrittweises Downgrade und Ausgleich einiger Unterschiede zwischen Browsern, sodass wir einfache on
verwenden können, um Ereignisse in Mainstream-Browsern zu überwachen:
// 一个简单的伪代码示例 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')
个人观点:所有的设计模式都不是凭空想象出来的,肯定是在开发的过程中,总结提炼出的一些高效的方法,这也就意味着,可能你并不需要在刚开始的时候就去生啃这些各种命名高大上的设计模式。
因为书中所说的场景可能并不全面,也可能针对某些语言,会存在更好的解决办法,所以生搬硬套可能并不会写出有灵魂的代码 :)
Das obige ist der detaillierte Inhalt vonAnwendung des Adapters in JavaScript (mit Beispielen). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!