面向切面編程

Q: 什么是食物?
A: 食物通常以碳水化合物腊瑟、脂肪、蛋白質或水構成棒呛,能夠借由進食或是飲用為人類或者生物提供營養(yǎng)或愉悅的物質澈圈。
   食物的來源可以是植物、動物或者其他界的生物巴帮,例如真菌溯泣,亦或發(fā)酵產(chǎn)品像是酒精。
   生物攝取食物后晰韵,被生物的細胞同化,提供能量熟妓,維持生命及刺激成長雪猪。 

前段時間討論到Java中的回調(diào)函數(shù)時,提到了面向切面(Aspect Oriented Programming)編程起愈。它是一種程序設計思維只恨,常常與面向對象(Object Oriented Programming)編程相比較,但是也常常被單獨拎出來討論抬虽。

OOP的誕生源自于人類與生俱來的分類抽象能力官觅,回想一下,讀小學的你阐污,是否就能輕而易舉地分辨“零食”和“正餐”的區(qū)別呢休涤?零食美味而充滿誘惑,但是對于你來說昂貴笛辟,而且吃太多存在挨罵的風險功氨,相對的,正餐則略顯的無聊和平淡手幢,但是在你餓了的時候往往能讓你的肚子不會咕咕叫捷凄。

于是自然而然你就可以將它們的共同點抽象出來,比如它們可以被食用围来,但是它們的味道跺涤、價格匈睁、食用時間乃至“副作用”之類的都不太一樣。它們中相同的屬性桶错,就可以分配給一個只對這些相同的屬性敏感的父元素航唆。而不同的部分,就單獨分配給父元素下屬的不同的子元素牛曹。這樣一來佛点,子元素就不光含有自己的屬性,也擁有了父元素的所有屬性黎比。

所以現(xiàn)在名詞解釋對你來說超营,會不會變得更容易呢?

面向切面

現(xiàn)在你知道了阅虫,事物中對于某些相同屬性的抽象演闭,構成了面向對象的基石。

來寫一個簡單的OOP的例子

    // JavaScript ES6

    class Person {
        constructor(name) {
            this.name = name;
        }
        greeting() {
            console.log(`hello, my name is ${this.name}, `);
        }
    }

    class Engineer extends Person {
        constructor(name, level) {
            super(name);
            this.level = level;
        }
        // override
        greeting() {
            super.greeting();
            console.log(`a ${this.level} Engineer.`);
        }
    }

    class Architect extends Engineer {
        constructor(name, level) {
            super(name, level);
        }
        design(work) {
            console.log(`right now, i\`m ${work}.`);
        }
        playGames(game, platform) {
            console.log(`${this.name} is playing ${game} on ${platform} now.`);
        }
    }

    let ted = new Architect('Ted', 'Junior');
    ted.greeting();
    ted.design('painting some blueprints');

    >>> 
    hello, my name is Ted,
    a Junior Engineer.
    right now, i'm painting some blueprints.

侵入式切面

假設我們想要在對象 Person 的所有方法執(zhí)行前颓帝,加入一段邏輯米碰。我們有什么好辦法呢?

代理函數(shù)是個很好的選擇购城,我們在進行具體的業(yè)務調(diào)用時吕座,直接調(diào)用一個代理函數(shù)就行了。


    function before(person, fn, ...args) {
        console.log('something running before');
        return fn.apply(person, args);
    }

函數(shù) before瘪板,將我們要調(diào)用的函數(shù)包裹起來吴趴,然后我們只需要這樣調(diào)用這個代理函數(shù),就能在其中的某個部分中添加邏輯侮攀。

    before(ted, ted.design, 'painting some blueprints');

上面的全局函數(shù)锣枝,還可以直接添加進對象中,防止被不必要的類或者方法使用兰英。


    Person.prototype.before = function (fn, ...args) {
        console.log('do sthing before');
        return fn.call(this, args);
    };

    ted.before(ted.design, 'painting some blueprints');

雖然這種形式大體上能解決我們的需求撇叁,但是這種寫法,仍然破壞了對象原有的調(diào)用形式畦贸。


    // 原來的調(diào)用形式
    ted.greeting();
    ted.playingGames('DotA2', 'PC');
    ted.design('painting some blueprints');

    // 代理函數(shù)的調(diào)用形式
    ted.before(ted.greeting);
    ted.before(ted.playingGames, 'DotA2', 'PC');
    ted.before(ted.design, 'painting some blueprints');

清一色的 before 函數(shù)陨闹,不僅寫起來頭暈,而且當你要改動的時候薄坏,所有調(diào)用這個代理函數(shù)的地方都要進行改動正林。這并不是我們想要的。

非侵入式切面

代理函數(shù)幫我們執(zhí)行了函數(shù)颤殴,雖然能按照我們的期望執(zhí)行程序觅廓,但我們更希望它直接返回函數(shù)給我們,這樣我們就無須費勁心思地去到處修改舊代碼涵但,同時往代碼中添加了新的功能杈绸。


    function before(originTarget, fn) {
        return function (...args) {
            console.log('do sthing before');
            return fn.apply(originTarget, args);
        };
    }
    ted.playGames = before(ted, ted.playGames);

    // 正常調(diào)用
    ted.playGames('DotA2', 'PC');

以上代碼還可以寫成更加通用的寫法


    function before (clazz, fn) {
        return function (...args) {
            console.log(`now time: ${new Date()}`);
            return clazz.prototype[fn].apply(this, args);
        }
    }
    ted.greeting = before(Person, 'greeting');

    // 正常調(diào)用
    ted.greeting();

程序中那些無法通過父元素所聚合的共同屬性帖蔓,但是又切實地影響到了程序的寫作——這種時候砰粹,切面編程就能發(fā)揮出它的用處攒磨。它將業(yè)務中的相同的部分抽象出來,組成一個個可拆卸的業(yè)務組件形庭。面向對象通過繼承和多態(tài)的縱軸讓代碼松耦合劫侧,而面向切面則是在業(yè)務并行展開的水平線上讓代碼松耦合埋酬。

中間件

提起AOP,總免不了讓人想到Java Spring框架中的監(jiān)聽器烧栋、攔截器写妥、過濾器。它們是典型的AOP編程思想的結晶——一條正常的程序流审姓,被幾個中間件攔截檢查珍特。

這啟發(fā)了我們,在程序設計上的一條新思路:程序暴露出一段執(zhí)行流魔吐,并且給開發(fā)者一把剪刀扎筒。它們可以隨意在允許的范圍內(nèi)剪開程序,并織入想要執(zhí)行的內(nèi)容酬姆。最后這一段執(zhí)行流合重新合并起來嗜桌,收入程序的深處。

簡單模擬一個中間件設計


    // 切入點函數(shù)隊列
    let fns = [];
    // 切點計數(shù)
    let fnCounter = 0;

    // 啟動函數(shù)
    function main() {
        next();
    }

    // 執(zhí)行下一個函數(shù)
    function next() {
        let fn = fns[fnCounter++];  // 取出函數(shù)數(shù)組里的下一個函數(shù)
        if (!fn) {    // 如果函數(shù)不存在,return
            return;
        }
        fn(next);   // 否則,執(zhí)行下一個函數(shù)
    }

    // 將自定義的函數(shù)推入函數(shù)隊列
    function processer(fn) {
        fns.push(fn);
    }

    function loginCheck(next) {
        if (...)
            next();
        else
            return;
    }

    function characterFilter(next) {
        // doing some character filtering
        next();
    }

    function mainService() {
        // 主業(yè)務
        console.log('some main services');
    }

    processer(characterFilter);
    processer(loginCheck);
    processer(mainService);
    main(); // 模擬程序啟動


原文地址: https://code.evink.me/2018/07/post/Aspect-Oriented-Programming/

?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末辞色,一起剝皮案震驚了整個濱河市骨宠,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌淫僻,老刑警劉巖诱篷,帶你破解...
    沈念sama閱讀 206,482評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件壶唤,死亡現(xiàn)場離奇詭異雳灵,居然都是意外死亡,警方通過查閱死者的電腦和手機闸盔,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,377評論 2 382
  • 文/潘曉璐 我一進店門悯辙,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人迎吵,你說我怎么就攤上這事躲撰。” “怎么了击费?”我有些...
    開封第一講書人閱讀 152,762評論 0 342
  • 文/不壞的土叔 我叫張陵拢蛋,是天一觀的道長。 經(jīng)常有香客問我蔫巩,道長谆棱,這世上最難降的妖魔是什么快压? 我笑而不...
    開封第一講書人閱讀 55,273評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮垃瞧,結果婚禮上蔫劣,老公的妹妹穿的比我還像新娘。我一直安慰自己个从,他們只是感情好脉幢,可當我...
    茶點故事閱讀 64,289評論 5 373
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嗦锐,像睡著了一般嫌松。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上意推,一...
    開封第一講書人閱讀 49,046評論 1 285
  • 那天豆瘫,我揣著相機與錄音,去河邊找鬼菊值。 笑死外驱,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的腻窒。 我是一名探鬼主播昵宇,決...
    沈念sama閱讀 38,351評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼儿子!你這毒婦竟也來了瓦哎?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 36,988評論 0 259
  • 序言:老撾萬榮一對情侶失蹤柔逼,失蹤者是張志新(化名)和其女友劉穎蒋譬,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體愉适,經(jīng)...
    沈念sama閱讀 43,476評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡犯助,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,948評論 2 324
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了维咸。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片剂买。...
    茶點故事閱讀 38,064評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖癌蓖,靈堂內(nèi)的尸體忽然破棺而出瞬哼,到底是詐尸還是另有隱情,我是刑警寧澤租副,帶...
    沈念sama閱讀 33,712評論 4 323
  • 正文 年R本政府宣布坐慰,位于F島的核電站,受9級特大地震影響用僧,放射性物質發(fā)生泄漏结胀。R本人自食惡果不足惜两残,卻給世界環(huán)境...
    茶點故事閱讀 39,261評論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望把跨。 院中可真熱鬧人弓,春花似錦、人聲如沸着逐。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,264評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽耸别。三九已至健芭,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間秀姐,已是汗流浹背慈迈。 一陣腳步聲響...
    開封第一講書人閱讀 31,486評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留省有,地道東北人痒留。 一個月前我還...
    沈念sama閱讀 45,511評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像蠢沿,于是被迫代替她去往敵國和親伸头。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,802評論 2 345

推薦閱讀更多精彩內(nèi)容

  • 本章內(nèi)容: 面向切面編程的基本原理 通過POJO創(chuàng)建切面 使用@AspectJ注解 為AspectJ切面注入依賴 ...
    謝隨安閱讀 3,127評論 0 9
  • AOP知識整理 AOP(Aspect-Oriented Programming):面向切面的編程舷蟀。OOP(Obje...
    wblearn閱讀 3,093評論 0 11
  • AOP(Aspect-Oriented Programming):面向切面的編程恤磷。OOP(Object-Orien...
    badcyc閱讀 292評論 0 1
  • 在我六歲的那一年,我要開始漫長的求學之路野宜,我猜想應該有很多的孩子和我當年的經(jīng)歷一樣扫步,因為沒有提前做好準備,結果到了...
    善行無痕閱讀 198評論 0 0
  • 第五章,我哄你 所以旬牲,那個男孩仿粹,在最后離開時告訴了她他的名字柯景蘇 而她也很快要離開搁吓, 白叔叔去尋醫(yī)了原茅,她等他...
    三炮英雄閱讀 254評論 0 0