您的位置:首页 > 编程语言

一个函数5行代码即可实现完整的面向方面AOP编程功能

2008-07-03 15:24 871 查看
你相信么,在JavaScript只需一个函数5行代码即可实现完整的面向方面AOP编程功能。这5行代码的功能包括:

无限层次的函数无害拦截

函数执行前拦截
检查函数的参数值
重新设定函数的参数值
函数执行后拦截
检查函数执行后的返回结果
重新设定函数的返回结果

虽然动态函数式语言的效率是一个存在的问题,但是对于它的高度灵活性,简直让人令人惊叹不已,剧赞。
这个小小的函数源自于和爱明兄的一次讨论:在javascript中不修改源代码的形式扩充新功能的完美方式。
至于为啥要不直接修改别人源代码库,你想,当你辛苦修改后,人家发布了一个新版本,你是不是又要重新
修改一次?如果修改的地方少还好,多了的话,嘿嘿!所以,不是你的东西,最好不要动,除非你确定要自
己完全维护所有的代码(如果你实在太闲)。

为了给开发人员一个榜样,俺不得不写一个patch样例,最开始俺写的patch方式是这样滴:
FCKEditingArea.prototype.FckMediaStart = FCKEditingArea.prototype.Start;
FCKEditingArea.prototype.Start = function( html, secondCall )
{
var sHeadExtra = '<link href="' + FCKConfig.PluginsPath + 'media/css/fck_media.css" rel="stylesheet" type="text/css" _fcktemp="true" />' ;
html = html.replace( FCKRegexLib.HeadCloser, sHeadExtra + '$&' ) ;
return this.FckMediaStart(html, secondCall);
}

俺觉得这种补丁方式是不太让我满意的

爱民兄提到他喜欢这样patch方式:
FCKEditingArea.prototype.Start = function( func ) {
return function( html ) {
html = html.replace( FCKRegexLib.HeadCloser, sHeadExtra + '$&' ) ;
return func.apply(this, arguments);
}
}(FCKEditingArea.prototype.Start);

这种方式的确不存在漏洞了,perfect,但是却把我彻底弄懵了,看得我头大啊!琢磨了好久才算明白过来。
不过从管理角度考虑,如果程序中到处都是这样的方式,那么将大大降低程序的可读性,增加维护代码的成本
(ps,要开发维护这样的代码,你不得不请JS高级程序员才行)。
为了限制匿名函数的滥用导致的可读性下降,俺写了一个Inject()函数的雏形(将匿名函数的使用限制在其中),
经过爱民兄修改,然后又是讨论,然后我们又修改,如此反复,达到这个最终版本(也许还不是,谁知道呢)。


好了,荣誉归于爱民,臭鸡蛋归于俺,闲话少说,看看代码吧,不算上注释,这个Inject函数正好5行。如果你清楚
的知道匿名函数的特点,那么这个函数,你就不难看懂,否则你就只能管用了。用法在注释的例子里,够简单吧。
/*
@desc inject the function
@param aOrgFunc the original function to be injected.
@param aBeforeExec this is called before the execution of the aOrgFunc.
you must return the arguments if you wanna modify the value of the aOrgFunc's arguments .
@param aAtferExec this is called after the execution of the aOrgFunc.
you must add a result argument at the last argument of the aAtferExec function if you wanna
get the result value of the aOrgFunc.
you must return the result if you wanna modify the result value of the aOrgFunc .

@Usage Obj.prototype.aMethod = Inject(Obj.prototype.aMethod, aFunctionBeforeExec[, aFunctionAtferExec]);
@author Aimingoo&Riceball

eg:
var doTest = function (a) {return a};
function beforeTest(a) { alert('before exec: a='+a); a += 3; return arguments;};
function afterTest(a, result) { alert('after exec: a='+a+'; result='+result); return result+5;};

doTest = Inject(doTest, beforeTest, afterTest);

alert (doTest(2));
the result should be 10.

*/
function Inject( aOrgFunc, aBeforeExec, aAtferExec ) {
return function() {
if (typeof(aBeforeExec) == 'function') arguments = aBeforeExec.apply(this, arguments) || arguments;
//convert arguments object to array
var Result, args = [].slice.call(arguments);
args.push(aOrgFunc.apply(this, args));
if (typeof(aAtferExec) == 'function') Result = aAtferExec.apply(this, args);
return (typeof(Result) != 'undefined')?Result:args.pop();
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐