《代碼整潔之道》讀書筆記(七)之系統(tǒng)整潔

建造和管理一座城市,你能自己掌管一切細節(jié)不脯?

恐怕不行府怯。每個城市都有一組組人管理不同的部分,供水系統(tǒng)防楷、供電系統(tǒng)牺丙、交通、執(zhí)法域帐、立法赘被,諸如此類。需要有人負責(zé)全局肖揣,有人負責(zé)細節(jié)民假。

城市能運轉(zhuǎn),還因為它演化出恰當(dāng)?shù)某橄蟮燃壓湍K龙优,好讓個人和他們所管理的“組件”即便在不了解全局時也能有效運轉(zhuǎn)羊异。

盡管軟件團隊往往也是這樣組織起來,但他們所致力的工作卻常常沒有同樣的關(guān)注面切分及抽象層級彤断。本文將討論如何在較高的抽象層級——系統(tǒng)層級——上保持整潔野舶。

1. 將系統(tǒng)的構(gòu)造和使用分開

構(gòu)造和使用是非常不一樣的過程。

軟件系統(tǒng)應(yīng)該將啟始過程和啟始過程之后的運行時邏輯分離開宰衙,在啟始過程中構(gòu)建應(yīng)用對象平道,也會存在互相糾纏的依賴關(guān)系。

不幸的是供炼,多數(shù)應(yīng)用程序都沒有做分離處理一屋。啟始過程代碼很特殊窘疮,被混雜到運行時邏輯。下列就是典型的情形:

public Service getService() {
    if (service == null) 
        service = new MyServiceImpl(...);       // Good enough for most cases?
    return service;
}

這就是所謂的延遲初始化冀墨,也有一些好處闸衫。在真正用到對象之前,無需操心這種架空構(gòu)造诽嘉,啟始時間也會更短蔚出,而且還能保證永遠不會返回null值。

然而虫腋,我們也得到了MyServiceImpl及其構(gòu)造器所需的一切的硬編碼依賴骄酗。不分解這些依賴關(guān)系就無法編譯,即便在運行時永不使用這種類型的對象岔乔。

如果MyServiceImpl是個重型對象酥筝,則測試也是個問題。我們必須確保在單元測試調(diào)用該方法之前雏门,就給servie指派恰當(dāng)?shù)臏y試替身嘿歌。由于構(gòu)造邏輯與運行過程想混雜,我們必須測所有的執(zhí)行路徑(例如茁影,null值測試及其代碼塊)宙帝。有了這些權(quán)責(zé),說明方法做了不止一件事募闲,輕微違反了單一職責(zé)原則步脓。

最糟糕的大概是我們不知道MyServiceImpl在所有情形中是否都是正確的對象。為什么該方法所屬類必須知道全局情形浩螺?我們是否真能知道在這里要用到正確的對象靴患?

我們應(yīng)該將對象構(gòu)造的啟始和設(shè)置過程從正常的運行時邏輯中分離出來。

1.1 分解main

將構(gòu)造與使用分開的方法之一是將全部構(gòu)造過程變遷到main或被稱之為main的模塊中要出,設(shè)計系統(tǒng)的其余部分時鸳君,假設(shè)所有對象都已正確構(gòu)造和設(shè)置。

控制流程很容易理解患蹂,main模塊創(chuàng)建系統(tǒng)所需的對象或颊,再傳遞給應(yīng)用程序,應(yīng)用程序只管使用传于。

1.2 工廠

應(yīng)用程序使用抽象工廠模式控制如何創(chuàng)建對象

1.3 依賴注入

有一種強大的機制可以實現(xiàn)分離構(gòu)造與使用囱挑,那就是依賴注入(Dependency Injection,DI)沼溜,控制反轉(zhuǎn)(Inversion of Control, IOC)在依賴管理中的一種應(yīng)用手段平挑。控制反轉(zhuǎn)將第二職責(zé)從對象中拿出來系草,轉(zhuǎn)移到另一個專注于此的對象中弹惦,從而遵循了單一職責(zé)原則否淤。

2. 擴容

“一開始就做對系統(tǒng)”純屬神話。我們應(yīng)該只去實現(xiàn)今天的用戶故事棠隐,然后重構(gòu),明天再擴展系統(tǒng)檐嚣、實現(xiàn)新的用戶故事助泽。這就是迭代和增量敏捷的精髓所在。測試驅(qū)動開發(fā)嚎京、重構(gòu)以及它們打造出來的整潔代碼嗡贺,在代碼層面保證了這個過程的實現(xiàn)。

與物理系統(tǒng)相比軟件系統(tǒng)比較獨特鞍帝。它們的架構(gòu)可以遞增式增長诫睬,只要我們持續(xù)將關(guān)注面恰當(dāng)?shù)厍蟹帧?/p>

面向方面編程(aspect-oriented programming, AOP)。在AOP中帕涌,被稱為方面(aspect)的模塊構(gòu)造指明了系統(tǒng)中哪些點的行為會以某種一致的方式被修改摄凡,從而支持某種特定的場景。這種說明是用某種簡介的聲明或編程機制來實現(xiàn)的蚓曼。

下面來看看Java中的三種方面或類似方面的機制亲澡。

3. Java代理

Java代理適用于簡單的情況,例如在單獨的對象或類中包裝方法調(diào)用纫版。然而床绪,JDK提供的動態(tài)代理僅能與接口協(xié)同工作。對于代理類其弊,你得使用字節(jié)碼操作庫癞己,比如CGLIB,ASM或Javassist梭伐。

Proxy API需要一個InvocationHandler對象痹雅,用來實現(xiàn)對代理的全部方法調(diào)用。

4. 純Java AOP框架

在數(shù)個Java框架中籽御,代理都是內(nèi)嵌的练慕,如Spring AOP和JBoss AOP等,從而能夠以純Java代碼(不適用AspectJ)實現(xiàn)面向方面編程技掏。

5. AspectJ的方面

通過方面來實現(xiàn)關(guān)注面切分的功能最全的工具是AspectJ語言铃将,一種提供“一流的”將方面作為模塊構(gòu)造處理支持的Java擴展。AspectJ的弱勢在于哑梳,需要采用幾種新工具劲阎,學(xué)習(xí)新語言構(gòu)造和使用方式。

6. 測試驅(qū)動系統(tǒng)架構(gòu)

通過方面式的手段切分關(guān)注面的威力不可低估鸠真。假設(shè)你能用POJO(舊式Java對象)編寫應(yīng)用程序的領(lǐng)域邏輯悯仙,在代碼層面與架構(gòu)關(guān)注面分離開龄毡,就有可能真正地用測試來驅(qū)動架構(gòu)。將架構(gòu)按需從簡單演化到精細锡垄,沒必要先做大設(shè)計沦零。

最佳的系統(tǒng)架構(gòu)由模塊化的關(guān)注面領(lǐng)域組成,每個關(guān)注面均用純Java(或其他語言)對象實現(xiàn)货岭。不同的領(lǐng)域之間用最不具有侵害性的方面或類方面工具整合起來路操。這種架構(gòu)能測試驅(qū)動,就像代碼一樣

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末千贯,一起剝皮案震驚了整個濱河市屯仗,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌搔谴,老刑警劉巖魁袜,帶你破解...
    沈念sama閱讀 211,376評論 6 491
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異敦第,居然都是意外死亡峰弹,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,126評論 2 385
  • 文/潘曉璐 我一進店門申尼,熙熙樓的掌柜王于貴愁眉苦臉地迎上來垮卓,“玉大人,你說我怎么就攤上這事师幕∷诎矗” “怎么了?”我有些...
    開封第一講書人閱讀 156,966評論 0 347
  • 文/不壞的土叔 我叫張陵霹粥,是天一觀的道長灭将。 經(jīng)常有香客問我,道長后控,這世上最難降的妖魔是什么庙曙? 我笑而不...
    開封第一講書人閱讀 56,432評論 1 283
  • 正文 為了忘掉前任,我火速辦了婚禮浩淘,結(jié)果婚禮上捌朴,老公的妹妹穿的比我還像新娘。我一直安慰自己张抄,他們只是感情好砂蔽,可當(dāng)我...
    茶點故事閱讀 65,519評論 6 385
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著署惯,像睡著了一般左驾。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,792評論 1 290
  • 那天诡右,我揣著相機與錄音安岂,去河邊找鬼。 笑死帆吻,一個胖子當(dāng)著我的面吹牛域那,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播猜煮,決...
    沈念sama閱讀 38,933評論 3 406
  • 文/蒼蘭香墨 我猛地睜開眼琉雳,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了友瘤?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 37,701評論 0 266
  • 序言:老撾萬榮一對情侶失蹤檐束,失蹤者是張志新(化名)和其女友劉穎辫秧,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體被丧,經(jīng)...
    沈念sama閱讀 44,143評論 1 303
  • 正文 獨居荒郊野嶺守林人離奇死亡盟戏,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,488評論 2 327
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了甥桂。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片柿究。...
    茶點故事閱讀 38,626評論 1 340
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖黄选,靈堂內(nèi)的尸體忽然破棺而出蝇摸,到底是詐尸還是另有隱情,我是刑警寧澤办陷,帶...
    沈念sama閱讀 34,292評論 4 329
  • 正文 年R本政府宣布貌夕,位于F島的核電站,受9級特大地震影響民镜,放射性物質(zhì)發(fā)生泄漏啡专。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,896評論 3 313
  • 文/蒙蒙 一制圈、第九天 我趴在偏房一處隱蔽的房頂上張望们童。 院中可真熱鬧,春花似錦鲸鹦、人聲如沸慧库。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,742評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽完沪。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間覆积,已是汗流浹背听皿。 一陣腳步聲響...
    開封第一講書人閱讀 31,977評論 1 265
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留宽档,地道東北人尉姨。 一個月前我還...
    沈念sama閱讀 46,324評論 2 360
  • 正文 我出身青樓,卻偏偏與公主長得像吗冤,于是被迫代替她去往敵國和親又厉。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 43,494評論 2 348

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,761評論 25 707
  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理椎瘟,服務(wù)發(fā)現(xiàn)覆致,斷路器,智...
    卡卡羅2017閱讀 134,629評論 18 139
  • 這部分主要是開源Java EE框架方面的內(nèi)容肺蔚,包括Hibernate煌妈、MyBatis、Spring宣羊、Spring ...
    雜貨鋪老板閱讀 1,357評論 0 2
  • _Jock羈閱讀 201評論 0 0
  • 夜色中璧诵,彩色的燈光把路邊的樹林照耀得色彩斑斕,遠遠看去仇冯,多像一楨楨彩色的圖畫之宿!漫步其中真的有一種人在畫中游的曼妙感覺!
    黯黯紅塵一路相伴閱讀 270評論 1 3