먼저 AOP 프로그래밍을 이야기하지 말고, 덕펀치 프로그래밍부터 시작해보자.
위키피디아에서 덕펀치라고 검색하면, 꼭 찾아야 할 항목이 몽키패치입니다. 설명에 따르면 몽키패치(monkey patch)라는 단어는 작전 중 조용히 코드를 바꾼다는 뜻의 게릴라 패치(guerrilla patch)에서 유래됐으며 게릴라(guerrilla)라는 단어는 고릴라와 발음이 같고, 후자는 원숭이(전자는 '고릴라'라는 뜻)와 비슷하다는 뜻이다. 마침내 For Monkey 패치로 진화했습니다.
덕펀치(Duck Punch)를 들어본 적이 없다면 덕타이핑(Duck Typing)은 들어보셨을 겁니다. 유명한 예를 들면, 오리를 식별하는 방법:
나는 오리처럼 걷고, 오리처럼 헤엄치고, 오리처럼 꽥꽥거리는 새를 보면 그 새를 오리라고 부릅니다.
네, 오리처럼 꽥꽥거리고 오리처럼 헤엄치는 동물을 찾으면 바로 오리일 거예요!
이 테스트는 다소 뻔하고 무의미해 보일 수도 있지만 매우 실용적입니다. 그리고 프로그래밍의 문제 유형(Javascript 또는 유사한 동적 언어의 경우 "인터페이스" 또는 "기본 클래스"를 구현하는 방법)을 해결하는 데 사용할 수 있습니다. 과거에 대해서는 전혀 신경 쓸 필요가 없습니다. 메소드 유형이나 매개변수가 사용할 때 필요한지 여부만 고려하면 됩니다.
rree사실 너무 멀리 가고 있습니다. 표현하고 싶은 것은 오리 펀치입니다. 오리 타이핑에서 진화한 것입니다.
오리처럼 걷고 오리처럼 말하면 오리겠죠? 그런데, 이것은 매우 생생한 농담을 생각나게 합니다:
의 힘을 시험하기 위해. 미국과 홍콩, 중국 본토의 경찰은 유엔이 세 숲에 토끼 세 마리를 배치해 누가 먼저 토끼를 찾는지 세 곳에서 경찰을 감시한다. 과제: 토끼를 찾아보세요. (가운데는 생략...) 결국 어느 나라 경찰 4명만 있었는데, 그들은 하루 동안 마작을 하다가 해질녘에 각자 지휘봉을 들고 비명소리를 들었습니다. 숲에서 나오는 동물들. 담배를 피우며 이야기를 나누며 웃었고, 그 뒤에는 코가 멍들고 얼굴이 부어오른 곰이 죽어가며 말했습니다. “더 이상 때리지 마세요. 그냥 토끼..."
동시에 오리 펀치 모드를 되돌릴 수도 있지만 이는 다음과 같습니다.오리펀치이긴 하지만 다소 폭력적이지만 효과적인 방법이다. 코드 구현에 있어서는 원본 코드가 필요한 기능과 호환되도록 만드는 것을 의미합니다. 예를 들어 Paul Irish의 블로그에 있는 다음 예는 다음과 같습니다.
var quack = someObject.quack; if (typeof quack == "function" && quck.length == arguLength) { // This thing can quack }로그인 후 복사
/** 我们都知道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')
(function($){ var _old = $.fn.method; $.fn.method = function(arg1,arg2){ if ( ... condition ... ) { return .... } else { // do the default return _old.apply(this,arguments); } }; })(jQuery);
Class Person { private int money; public void pay(int price) { this.money = this.money - price; } }
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项目
这一篇一定让你失望了,代码简单又寥寥无几。本篇主要在于介绍有关Javascript의 AOP 프로그래밍에 대해 이야기和AOP的这几类思想,我想编程的乐趣不仅仅在于落实在编码上,更在于整个架构的设计。提高代码的可维护性和可拓展性会比高深莫测的代码更重要。
以上就是聊Javascript中的AOP编程的内容,更多相关内容请关注PHP中文网(www.php.cn)!