Reden wir nicht zuerst über die AOP-Programmierung, sondern beginnen wir mit der Duck Punch-Programmierung.
Wenn Sie in Wikipedia nach Duck Punch suchen, sollten Sie den Eintrag Monkey Patch finden. Der Erklärung zufolge stammt das Wort Monkey Patch von Guerilla Patch, was bedeutet, dass der Code während des Betriebs stillschweigend geändert wird. Das Wort Guerilla hat die gleiche Aussprache wie Gorilla, und letzteres bedeutet ähnlich wie Affe (ersteres bedeutet „Gorilla“) entwickelte sich schließlich zu For Monkey Patch.
Wenn Sie noch nie von Duck Punch gehört haben, haben Sie vielleicht schon von Duck Typing gehört. Um ein beliebtes Beispiel zu nennen, wie man eine Ente erkennt:
Wenn ich einen Vogel sehe, der wie eine Ente geht und schwimmt wie eine Ente und quakt wie eine Ente, nenne ich diesen Vogel eine Ente.
Ja, wenn ich ein Tier finde, das quakt wie eine Ente und schwimmt wie eine Ente, dann wäre es eine Ente!
Dieser Test mag ein wenig offensichtlich und unsinnig erscheinen, aber er ist sehr praktisch. Und es kann verwendet werden, um eine Art Problem in der Programmierung zu lösen – wie implementiert man für Javascript oder ähnliche dynamische Sprachen „Schnittstelle“ oder „Basisklasse“? Wir müssen uns überhaupt nicht um ihre Vergangenheit kümmern, wenn wir sie verwenden:
var quack = someObject.quack; if (typeof quack == "function" && quck.length == arguLength) { // This thing can quack }
Tatsächlich gehe ich zu weit. Was ich ausdrücken möchte, ist Ente. Eigentlich hat sich Punch aus der Enteneingabe entwickelt:
Wenn es wie eine Ente läuft und wie eine Ente spricht, ist es eine Ente, oder? Um den Lärm zu erzeugen, den Sie wollen, müssen Sie die Ente einfach schlagen, bis sie das zurückgibt, was Sie erwarten ... Übrigens erinnert mich das an einen sehr anschaulichen Witz:
Um Um die Stärke der Polizei in den Vereinigten Staaten, Hongkong und Festlandchina zu testen, haben die Vereinten Nationen drei Kaninchen in drei Wäldern platziert. Welcher örtliche Polizist wird das Kaninchen zuerst finden? Aufgabe: Finde das Kaninchen. (Die Mitte entfällt...) Schließlich waren es nur vier Polizisten aus einem bestimmten Land. Sie spielten einen Tag lang Mahjong, jeder von ihnen nahm einen Schlagstock und betrat innerhalb von fünf Minuten die Schreie Von Tieren, die aus dem Wald kamen, kam er redend und lachend heraus, während er eine Zigarette rauchte, und hinter ihm war ein Bär mit einer verletzten Nase und einem geschwollenen Gesicht, der sterbend sagte: „Schlag mich nicht mehr, ich bin nur ein.“ Kaninchen..."
Obwohl Entenschlag etwas heftig, aber dennoch eine wirksame Methode. Bei der Code-Implementierung geht es darum, den Originalcode mit den von uns benötigten Funktionen kompatibel zu machen. Zum Beispiel dieses Beispiel auf dem Blog von Paul Irish:
Gleichzeitig kann der Duck-Punch-Modus überschrieben werden, aber es ist einfach so:
/** 我们都知道jQuery的`$.css`方法可以通过使用颜色的名称给元素进行颜色赋值。 但jQuery内置的颜色并非是那么丰富,如果我们想添加我们自定义的颜色名称应该怎么办?比如我们想添加`Burnt Sienna`这个颜色 */ (function($){ // 把原方法暂存起来: var _oldcss = $.fn.css; // 重写原方法: $.fn.css = function(prop,value){ // 把自定义的颜色写进分支判断里,特殊情况特殊处理 if (/^background-?color$/i.test(prop) && value.toLowerCase() === 'burnt sienna') { return _oldcss.call(this,prop,'#EA7E5D'); // 一般情况一般处理,调用原方法 } else { return _oldcss.apply(this,arguments); } }; })(jQuery); // 使用方法: jQuery(document.body).css('backgroundColor','burnt sienna')
Aber da Hier liegt ein Problem vor: Die ursprüngliche Methode muss geändert werden. Dies verstößt gegen das „Offen-Geschlossen“-Prinzip, das für Erweiterungen offen und für Änderungen geschlossen sein sollte. Wie kann dieses Problem gelöst werden? Verwenden Sie die AOP-Programmierung.
(function($){ var _old = $.fn.method; $.fn.method = function(arg1,arg2){ if ( ... condition ... ) { return .... } else { // do the default return _old.apply(this,arguments); } }; })(jQuery);
Aber normalerweise ist die tatsächliche Situation komplizierter. Beispielsweise müssen wir der Zahlungsmethode eine Autorisierungserkennung hinzufügen oder Protokolle für Statistiken oder sogar fehlertoleranten Code senden. Der Code sieht also so aus:
Class Person { private int money; public void pay(int price) { this.money = this.money - price; } }
Noch beängstigender ist, dass ähnlicher Code zu anderen Methoden hinzugefügt werden muss. Auf diese Weise sind die Wartbarkeit und Lesbarkeit des Codes zu einem großen Problem geworden. Wir hoffen, diese verstreuten, aber gemeinsamen, nicht geschäftlichen Codes zu sammeln und sie benutzerfreundlicher zu nutzen und zu verwalten. Dies ist Aspektprogrammierung. Durch die Aspektprogrammierung wird die Wiederverwendung von Code erreicht, indem eine Änderung des Remotecodes vermieden wird. Es ist, als würde man verschiedene Objekte horizontal schneiden und sich auf die Transformation interner Methoden konzentrieren. Bei der objektorientierten Programmierung wird dem gesamten Architekturdesign mehr Aufmerksamkeit geschenkt.
Class Person { private int money public void pay(price) { try { if (checkAuthorize() == true) { this.money = this.money - price; sendLog(); } } catch (Exception e) { } } }
AOP中有一些概念需要介绍一下,虽然我们不一定要严格执行
joint-point:原业务方法;
advice:拦截方式
point-cut:拦截方法
关于这三个概念我们可以串起来可以这么理解:
当我们使用AOP改造一个原业务方法(joint-point)时,比如加入日志发送功能(point-cut),我们要考虑在什么情况下(advice)发送日志,是在业务方法触发之前还是之后;还是在抛出异常的时候,还是由日志发送是否成功再决定是否执行业务方法。
比如gihub上的meld这个开源项目,就是一个很典型的AOP类库,我们看看它的API:
// 假设我们有一个对象myObject, 并且该对象有一个doSomething方法: var myObject = { doSomething: function(a, b) { return a + b; } }; // 现在我们想拓展它,在执行那个方法之后打印出刚刚执行的结果: var remover = meld.after(myObject, 'doSomething', function(result) { console.log('myObject.doSomething returned: ' + result); }); // 试试执行看: myObject.doSomething(1, 2); // Logs: "myObject.doSomething returned: 3" // 这个时候我们想移除刚刚的修改: remover.remove();
由此可以看出,AOP接口通常需要三个参数,被修改的对象,被修改对象的方法(joint-point),以及触发的时机(apce),还有触发的动作(point-cut)。上面说了那么多的概念,现在可能要让各位失望了,Javascript的实现原理其实非常简单
function doAfter(target, method, afterFunc){ var func = target[method]; return function(){ var res = func.apply(this, arguments); afterFunc.apply(this, arguments); return res; }; }
当然,如果想看到更完备的解决方案和代码可以参考上面所说的meld项目
这一篇一定让你失望了,代码简单又寥寥无几。本篇主要在于介绍有关Sprechen Sie über die AOP-Programmierung in Javascript和AOP的这几类思想,我想编程的乐趣不仅仅在于落实在编码上,更在于整个架构的设计。提高代码的可维护性和可拓展性会比高深莫测的代码更重要。
以上就是聊Javascript中的AOP编程的内容,更多相关内容请关注PHP中文网(www.php.cn)!