本書是設(shè)計(jì)模式領(lǐng)域公認(rèn)的3本經(jīng)典著作之一,“極具趣味,容易理解,但講解又極為嚴(yán)謹(jǐn)和透徹”是本書的寫作風(fēng)格和方法的最大特點(diǎn)。第1版2010年出版,暢銷至今,廣受好評(píng),是該領(lǐng)域的里程碑著作。深刻解讀6大設(shè)計(jì)原則和28種設(shè)計(jì)模式的準(zhǔn)確定義、應(yīng)用方法和最佳實(shí)踐,全方位比較各種同類模式之間的異同,詳細(xì)講解將不同的模式組合使用的方法。第2版在第1版的基礎(chǔ)上有兩方面的改進(jìn),一方面結(jié)合讀者的意見和建議對(duì)原有內(nèi)容中的瑕疵進(jìn)行了修正和完善,另一方面增加了4種新的設(shè)計(jì)模式,希望這一版能為廣大程序員們奉上一場(chǎng)更加完美的設(shè)計(jì)模式盛宴!
全書共38章,分為五部分:第一部分(第1~6章),以一種全新的視角對(duì)面向?qū)ο蟪绦蛟O(shè)計(jì)的6大原則進(jìn)行了深刻解讀,旨在讓讀者能更深刻且準(zhǔn)確地理解這些原則,為后面的學(xué)習(xí)打下基礎(chǔ);第二部分(第7~29章)通過大量生動(dòng)的案例講解和分析了23種最常用的設(shè)計(jì)模式,并進(jìn)行了擴(kuò)展講解,通俗易懂,趣味性極強(qiáng)而又緊扣模式的核心;第三部分(第30~33章)對(duì)同類型和相關(guān)聯(lián)的模式進(jìn)行了深入分析和比較,旨在闡明各種設(shè)計(jì)模式之間的差別以及它們的理想應(yīng)用場(chǎng)景;第四部分(第34~36章)探討了如何在實(shí)際開發(fā)中將各種設(shè)計(jì)模式混合起來使用,以發(fā)揮設(shè)計(jì)模式的最大效用;第五部分(第37~38章)是本書的擴(kuò)展篇,首先從實(shí)現(xiàn)的角度對(duì)MVC框架的原理進(jìn)行了深入分析,然后講解了5種新的設(shè)計(jì)模式的原理、意圖和最佳實(shí)踐。本書最后附有一份精美的設(shè)計(jì)模式彩圖,可以裁剪,便于參考。
(1) 暢銷書全新升級(jí),第1版廣受好評(píng),被譽(yù)為設(shè)計(jì)模式領(lǐng)域最具趣味、最易理解且又講解極為透徹的一本書,程序員公認(rèn)的3本經(jīng)典設(shè)計(jì)模式著作之一(2) 深刻解讀6大設(shè)計(jì)原則和28種設(shè)計(jì)模式的準(zhǔn)確定義、應(yīng)用方法和最佳實(shí)踐,全方位比較各種同類模式之間的異同,詳細(xì)講解將不同的模式組合使用的方法
秦小波 資深軟件開發(fā)工程師、系統(tǒng)分析師和架構(gòu)師(獲Sun架構(gòu)師認(rèn)證),從事軟件開發(fā)工作10余年,實(shí)踐經(jīng)驗(yàn)極其豐富。精通設(shè)計(jì)模式,對(duì)設(shè)計(jì)模式有深刻的認(rèn)識(shí)和獨(dú)到見解,經(jīng)過長(zhǎng)期大量的實(shí)踐和總結(jié),創(chuàng)造性地提出新的設(shè)計(jì)模式。資深Java技術(shù)專家,精通Spring、Struts 2、Hibernate、iBatis、jBPM等Java技術(shù),在企業(yè)級(jí)Java應(yīng)用領(lǐng)域積累了大量經(jīng)驗(yàn),對(duì)基于ESB、BPEL的服務(wù)集成技術(shù)也有深入的認(rèn)識(shí)。此外,還是一位優(yōu)秀的DBA,具有IBM DB2 DBA資格認(rèn)證,對(duì)海量數(shù)據(jù)處理有深入的研究。著有暢銷書《編寫高質(zhì)量代碼:改善Java程序的151個(gè)建議》,廣受讀者好評(píng)!
"前 言
第一部分 大旗不揮,誰敢沖
鋒—6大設(shè)計(jì)原則全新解讀
第1章 單一職責(zé)原則 2
1.1 我是“!鳖,我可以擔(dān)任多職嗎 2
1.2 絕殺技,打破你的傳統(tǒng)思維 3
1.3 我單純,所以我快樂 6
1.4 最佳實(shí)踐 7
第2章 里氏替換原則 8
2.1 愛恨糾葛的父子關(guān)系 8
2.2 糾紛不斷,規(guī)則壓制 9
2.3 最佳實(shí)踐 18
第3章 依賴倒置原則 19
3.1 依賴倒置原則的定義 19
3.2 言而無信,你太需要契約 20 "前 言
第一部分 大旗不揮,誰敢沖
鋒—6大設(shè)計(jì)原則全新解讀
第1章 單一職責(zé)原則 2
1.1 我是“!鳖,我可以擔(dān)任多職嗎 2
1.2 絕殺技,打破你的傳統(tǒng)思維 3
1.3 我單純,所以我快樂 6
1.4 最佳實(shí)踐 7
第2章 里氏替換原則 8
2.1 愛恨糾葛的父子關(guān)系 8
2.2 糾紛不斷,規(guī)則壓制 9
2.3 最佳實(shí)踐 18
第3章 依賴倒置原則 19
3.1 依賴倒置原則的定義 19
3.2 言而無信,你太需要契約 20
3.3 依賴的三種寫法 25
3.4 最佳實(shí)踐 26
第4章 接口隔離原則 28
4.1 接口隔離原則的定義 28
4.2 美女何其多,觀點(diǎn)各不同 29
4.3 保證接口的純潔性 33
4.4 最佳實(shí)踐 35
第5章 迪米特法則 36
5.1 迪米特法則的定義 36
5.2 我的知識(shí)你知道得越少越好 36
5.3 最佳實(shí)踐 43
第6章 開閉原則 44
6.1 開閉原則的定義 44
6.2 開閉原則的廬山真面目 44
6.3 為什么要采用開閉原則 49
6.4 如何使用開閉原則 51
6.5 最佳實(shí)踐 55
第二部分 真刀實(shí)槍—23種設(shè)計(jì)模式完美演繹
第7章 單例模式 58
7.1 我是皇帝我獨(dú)苗 58
7.2 單例模式的定義 59
7.3 單例模式的應(yīng)用 60
7.3.1 單例模式的優(yōu)點(diǎn) 60
7.3.2 單例模式的缺點(diǎn) 60
7.3.3 單例模式的使用場(chǎng)景 61
7.3.4 單例模式的注意事項(xiàng) 61
7.4 單例模式的擴(kuò)展 62
7.5 最佳實(shí)踐 64
第8章 工廠方法模式 65
8.1 女媧造人的故事 65
8.2 工廠方法模式的定義 69
8.3 工廠方法模式的應(yīng)用 70
8.3.1 工廠方法模式的優(yōu)點(diǎn) 70
8.3.2 工廠方法模式的使用場(chǎng)景 71
8.4 工廠方法模式的擴(kuò)展 71
8.5 最佳實(shí)踐 77
第9章 抽象工廠模式 78
9.1 女媧的失誤 78
9.2 抽象工廠模式的定義 83
9.3 抽象工廠模式的應(yīng)用 86
9.3.1 抽象工廠模式的優(yōu)點(diǎn) 86
9.3.2 抽象工廠模式的缺點(diǎn) 86
9.3.3 抽象工廠模式的使用場(chǎng)景 86
9.3.4 抽象工廠模式的注意事項(xiàng) 86
9.4 最佳實(shí)踐 87
第10章 模板方法模式 88
10.1 輝煌工程—制造悍馬 88
10.2 模板方法模式的定義 93
10.3 模板方法模式的應(yīng)用 94
10.3.1 模板方法模式的優(yōu)點(diǎn) 94
10.3.2 模板方法模式的缺點(diǎn) 95
10.3.3 模板方法模式的使用場(chǎng)景 95
10.4 模板方法模式的擴(kuò)展 95
10.5 最佳實(shí)踐 99
第11章 建造者模式 100
11.1 變化是永恒的 100
11.2 建造者模式的定義 109
11.3 建造者模式的應(yīng)用 111
11.3.1 建造者模式的優(yōu)點(diǎn) 111
11.3.2 建造者模式的使用場(chǎng)景 111
11.3.3 建造者模式的注意事項(xiàng) 111
11.4 建造者模式的擴(kuò)展 111
11.5 最佳實(shí)踐 112
第12章 代理模式 113
12.1 我是游戲至尊 113
12.2 代理模式的定義 116
12.3 代理模式的應(yīng)用 118
12.3.1 代理模式的優(yōu)點(diǎn) 118
12.3.2 代理模式的使用場(chǎng)景 119
12.4 代理模式的擴(kuò)展 119
12.4.1 普通代理 119
12.4.2 強(qiáng)制代理 121
12.4.3 代理是有個(gè)性的 126
12.4.4 動(dòng)態(tài)代理 128
12.5 最佳實(shí)踐 134
第13章 原型模式 135
13.1 個(gè)性化電子賬單 135
13.2 原型模式的定義 141
13.3 原型模式的應(yīng)用 142
13.3.1 原型模式的優(yōu)點(diǎn) 142
13.3.2 原型模式的使用場(chǎng)景 142
13.4 原型模式的注意事項(xiàng) 143
13.4.1 構(gòu)造函數(shù)不會(huì)被執(zhí)行 143
13.4.2 淺拷貝和深拷貝 144
13.4.3 clone與final兩個(gè)冤家 146
13.5 最佳實(shí)踐 146
第14章 中介者模式 147
14.1 進(jìn)銷存管理是這個(gè)樣子的嗎 147
14.2 中介者模式的定義 156
14.3 中介者模式的應(yīng)用 159
14.3.1 中介者模式的優(yōu)點(diǎn) 159
14.3.2 中介者模式的缺點(diǎn) 159
14.3.3 中介者模式的使用場(chǎng)景 159
14.4 中介者模式的實(shí)際應(yīng)用 160
14.5 最佳實(shí)踐 161
第15章 命令模式 162
15.1 項(xiàng)目經(jīng)理也難當(dāng) 162
15.2 命令模式的定義 170
15.3 命令模式的應(yīng)用 173
15.3.1 命令模式的優(yōu)點(diǎn) 173
15.3.2 命令模式的缺點(diǎn) 173
15.3.3 命令模式的使用場(chǎng)景 173
15.4 命令模式的擴(kuò)展 173
15.4.1 未講完的故事 173
15.4.2 反悔問題 174
15.5 最佳實(shí)踐 175
第16章 責(zé)任鏈模式 178
16.1 古代婦女的枷鎖—“三從四德” 178
16.2 責(zé)任鏈模式的定義 186
16.3 責(zé)任鏈模式的應(yīng)用 189
16.3.1 責(zé)任鏈模式的優(yōu)點(diǎn) 189
16.3.2 責(zé)任鏈模式的缺點(diǎn) 190
16.3.3 責(zé)任鏈模式的注意事項(xiàng) 190
16.4 最佳實(shí)踐 190
第17章 裝飾模式 192
17.1 罪惡的成績(jī)單 192
17.2 裝飾模式的定義 198
17.3 裝飾模式應(yīng)用 201
17.3.1 裝飾模式的優(yōu)點(diǎn) 201
17.3.2 裝飾模式的缺點(diǎn) 201
17.3.3 裝飾模式的使用場(chǎng)景 201
17.4 最佳實(shí)踐 201
第18章 策略模式 203
18.1 劉備江東娶妻,趙云他容易嗎 203
18.2 策略模式的定義 206
18.3 策略模式的應(yīng)用 208
18.3.1 策略模式的優(yōu)點(diǎn) 208
18.3.2 策略模式的缺點(diǎn) 208
18.3.3 策略模式的使用場(chǎng)景 209
18.3.4 策略模式的注意事項(xiàng) 209
18.4 策略模式的擴(kuò)展 209
18.5 最佳實(shí)踐 214
第19章 適配器模式 215
19.1 業(yè)務(wù)發(fā)展—上帝才能控制 215
19.2 適配器模式的定義 221
19.3 適配器模式的應(yīng)用 223
19.3.1 適配器模式的優(yōu)點(diǎn) 223
19.3.2 適配器模式的使用場(chǎng)景 224
19.3.3 適配器模式的注意事項(xiàng) 224
19.4 適配器模式的擴(kuò)展 224
19.5 最佳實(shí)踐 229
第20章 迭代器模式 230
20.1 整理項(xiàng)目信息—苦差事 230
20.2 迭代器模式的定義 236
20.3 迭代器模式的應(yīng)用 239
20.4 最佳實(shí)踐 239
第21章 組合模式 240
21.1 公司的人事架構(gòu)是這樣的嗎 240
21.2 組合模式的定義 253
21.3 組合模式的應(yīng)用 255
21.3.1 組合模式的優(yōu)點(diǎn) 255
21.3.2 組合模式的缺點(diǎn) 256
21.3.3 組合模式的使用場(chǎng)景 256
21.3.4 組合模式的注意事項(xiàng) 256
21.4 組合模式的擴(kuò)展 256
21.4.1 真實(shí)的組合模式 256
21.4.2 透明的組合模式 257
21.4.3 組合模式的遍歷 259
21.5 最佳實(shí)踐 260
第22章 觀察者模式 262
22.1 韓非子身邊的臥底是誰派來的 262
22.2 觀察者模式的定義 271
22.3 觀察者模式的應(yīng)用 273
22.3.1 觀察者模式的優(yōu)點(diǎn) 273
22.3.2 觀察者模式的缺點(diǎn) 274
22.3.3 觀察者模式的使用場(chǎng)景 274
22.3.4 觀察者模式的注意事項(xiàng) 274
22.4 觀察者模式的擴(kuò)展 275
22.4.1 Java世界中的觀察者模式 275
22.4.2 項(xiàng)目中真實(shí)的觀察者模式 276
22.4.3 訂閱發(fā)布模型 277
22.5 最佳實(shí)踐 277
第23章 門面模式 278
23.1 我要投遞信件 278
23.2 門面模式的定義 283
23.3 門面模式的應(yīng)用 284
23.3.1 門面模式的優(yōu)點(diǎn) 284
23.3.2 門面模式的缺點(diǎn) 285
23.3.3 門面模式的使用場(chǎng)景 285
23.4 門面模式的注意事項(xiàng) 285
23.4.1 一個(gè)子系統(tǒng)可以有多個(gè)門面 285
23.4.2 門面不參與子系統(tǒng)內(nèi)的業(yè)務(wù)邏輯 286
23.5 最佳實(shí)踐 288
第24章 備忘錄模式 289
24.1 如此追女孩子,你還不樂 289
24.2 備忘錄模式的定義 294
24.3 備忘錄模式的應(yīng)用 297
24.3.1 備忘錄模式的使用場(chǎng)景 297
24.3.2 備忘錄模式的注意事項(xiàng) 297
24.4 備忘錄模式的擴(kuò)展 297
24.4.1 clone方式的備忘錄 297
24.4.2 多狀態(tài)的備忘錄模式 300
24.4.3 多備份的備忘錄 304
24.4.4 封裝得更好一點(diǎn) 305
24.5 最佳實(shí)踐 307
第25章 訪問者模式 308
25.1 員工的隱私何在 308
25.2 訪問者模式的定義 316
25.3 訪問者模式的應(yīng)用 320
25.3.1 訪問者模式的優(yōu)點(diǎn) 320
25.3.2 訪問者模式的缺點(diǎn) 320
25.3.3 訪問者模式的使用場(chǎng)景 320
25.4 訪問者模式的擴(kuò)展 321
25.4.1 統(tǒng)計(jì)功能 321
25.4.2 多個(gè)訪問者 323
25.4.3 雙分派 326
25.5 最佳實(shí)踐 328
第26章 狀態(tài)模式 329
26.1 城市的縱向發(fā)展功臣—電梯 329
26.2 狀態(tài)模式的定義 341
26.3 狀態(tài)模式的應(yīng)用 343
26.3.1 狀態(tài)模式的優(yōu)點(diǎn) 343
26.3.2 狀態(tài)模式的缺點(diǎn) 344
26.3.3 狀態(tài)模式的使用場(chǎng)景 344
26.3.4 狀態(tài)模式的注意事項(xiàng) 344
26.4 最佳實(shí)踐 344
第27章 解釋器模式 346
27.1 四則運(yùn)算你會(huì)嗎 346
27.2 解釋器模式的定義 352
27.3 解釋器模式的應(yīng)用 354
27.3.1 解釋器模式的優(yōu)點(diǎn) 354
27.3.2 解釋器模式的缺點(diǎn) 354
27.3.3 解釋器模式使用的場(chǎng)景 355
27.3.4 解釋器模式的注意事項(xiàng) 355
27.4 最佳實(shí)踐 355
第28章 享元模式 356
28.1 內(nèi)存溢出,司空見慣 356
28.2 享元模式的定義 361
28.3 享元模式的應(yīng)用 364
28.3.1 享元模式的優(yōu)點(diǎn)和缺點(diǎn) 364
28.3.2 享元模式的使用場(chǎng)景 364
28.4 享元模式的擴(kuò)展 365
28.4.1 線程安全的問題 365
28.4.2 性能平衡 366
28.5 最佳實(shí)踐 369
第29章 橋梁模式 371
29.1 我有一個(gè)夢(mèng)想 371
29.2 橋梁模式的定義 379
29.3 橋梁模式的應(yīng)用 381
29.3.1 橋梁模式的優(yōu)點(diǎn) 381
29.3.2 橋梁模式的使用場(chǎng)景 382
29.3.3 橋梁模式的注意事項(xiàng) 382
29.4 最佳實(shí)踐 382
第三部分 誰的地盤誰做主—設(shè)計(jì)模式PK
第30章 創(chuàng)建類模式大PK 384
30.1 工廠方法模式VS建造者模式 384
30.1.1 按工廠方法建造超人 384
30.1.2 按建造者模式建造超人 386
30.1.3 最佳實(shí)踐 389
30.2 抽象工廠模式VS建造者模式 390
30.2.1 按抽象工廠模式生產(chǎn)車輛 390
30.2.2 按建造者模式生產(chǎn)車輛 394
30.2.3 最佳實(shí)踐 399
第31章 結(jié)構(gòu)類模式大PK 400
31.1 代理模式VS裝飾模式 400
31.1.1 代理模式 400
31.1.2 裝飾模式 402
31.1.3 最佳實(shí)踐 403
31.2 裝飾模式VS適配器模式 404
31.2.1 用裝飾模式描述丑小鴨 404
31.2.2 用適配器模式實(shí)現(xiàn)丑小鴨 407
31.2.3 最佳實(shí)踐 410
第32章 行為類模式大PK 411
32.1 命令模式VS策略模式 411
32.1.1 策略模式實(shí)現(xiàn)壓縮算法 411
32.1.2 命令模式實(shí)現(xiàn)壓縮算法 414
32.1.3 小結(jié) 419
32.2 策略模式VS狀態(tài)模式 420
32.2.1 策略模式實(shí)現(xiàn)人生 420
32.2.2 狀態(tài)模式實(shí)現(xiàn)人生 423
32.2.3 小結(jié) 425
32.3 觀察者模式VS責(zé)任鏈模式 426
32.3.1 責(zé)任鏈模式實(shí)現(xiàn)DNS
解析過程 427
32.3.2 觸發(fā)鏈模式實(shí)現(xiàn)DNS
解析過程 432
32.3.3 小結(jié) 437
第33章 跨戰(zhàn)區(qū)PK 438
33.1 策略模式VS橋梁模式 438
33.1.1 策略模式實(shí)現(xiàn)郵件發(fā)送 439
33.1.2 橋梁模式實(shí)現(xiàn)郵件發(fā)送 442
33.1.3 最佳實(shí)踐 445
33.2 門面模式VS中介者模式 446
33.2.1 中介者模式實(shí)現(xiàn)工資計(jì)算 446
33.2.2 門面模式實(shí)現(xiàn)工資計(jì)算 451
33.2.3 最佳實(shí)踐 454
33.3 包裝模式群PK 455
33.3.1 代理模式 455
33.3.2 裝飾模式 457
33.3.3 適配器模式 459
33.3.4 橋梁模式 461
33.3.5 最佳實(shí)踐 464
第四部分 完美世界—設(shè)計(jì)模式混編
第34章 命令模式+責(zé)任鏈模式 466
34.1 搬移UNIX的命令 466
34.2 混編小結(jié) 481
第35章 工廠方法模式+策略模式 483
35.1 迷你版的交易系統(tǒng) 483
35.2 混編小結(jié) 493
第36章 觀察者模式+中介者模式 495
36.1 事件觸發(fā)器的開發(fā) 495
36.2 混編小結(jié) 508
第五部分 擴(kuò)展篇<
" 大旗不揮,誰敢沖鋒
—6大設(shè)計(jì)原則全新解讀
第1章 單一職責(zé)原則
第2章 里氏替換原則
第3章 依賴倒置原則
第4章 接口隔離原則
第5章 迪米特法則
第6章 開閉原則
單一職責(zé)原則
1.1 我是“!鳖,我可以擔(dān)任多職嗎
單一職責(zé)原則的英文名稱是Single Responsibility Principle,簡(jiǎn)稱是SRP。這個(gè)設(shè)計(jì)原則備受爭(zhēng)議,只要你想和別人爭(zhēng)執(zhí)、慪氣或者是吵架,這個(gè)原則是屢試不爽的。如果你是老大,看到一個(gè)接口或類是這樣或那樣設(shè)計(jì)的,你就問一句:“你設(shè)計(jì)的類符合SRP原則嗎?”保準(zhǔn)對(duì)方立馬“萎縮”掉,而且還一臉崇拜地看著你,心想:“老大確實(shí)英明”。這個(gè)原則存在爭(zhēng)議之處在哪里呢?就是對(duì)職責(zé)的定義,什么是類的職責(zé),以及怎么劃分類的職責(zé)。我們先舉個(gè)例子來說明什么是單一職責(zé)原則。
只要做過項(xiàng)目,肯定要接觸到用戶、機(jī)構(gòu)、角色管理這些模塊,基本上使用的都是RBAC模型(Role-Based Access Control,基于角色的訪問控制,通過分配和取消角色來完成用戶權(quán)限的授予和取消,使動(dòng)作主體(用戶)與資源的行為(權(quán)限)分離),確實(shí)是一個(gè)很好的解決辦法。我們這里要講的是用戶管理、修改用戶的信息、增加機(jī)構(gòu)(一個(gè)人屬于多個(gè)機(jī)構(gòu))、增加角色等,用戶有這么多的信息和行為要維護(hù),我們就把這些寫到一個(gè)接口中,都是用戶管理類嘛,我們先來看它的類圖,如圖1-1所示。
太Easy的類圖了,我相信,即使是一個(gè)初級(jí)的程序員也可以看出這個(gè)接口設(shè)計(jì)得有問題,用戶的屬性和用戶的行為沒有分開,這是一個(gè)嚴(yán)重的錯(cuò)誤!這個(gè)接口確實(shí)設(shè)計(jì)得一團(tuán)糟,應(yīng)該把用戶的信息抽取成一個(gè)BO(Business Object,業(yè)務(wù)對(duì)象),把行為抽取成一個(gè)Biz(Business Logic,業(yè)務(wù)邏輯),按照這個(gè)思路對(duì)類圖進(jìn)行修正,如圖1-2所示。
重新拆封成兩個(gè)接口,IUserBO負(fù)責(zé)用戶的屬性,簡(jiǎn)單地說,IUserBO的職責(zé)就是收集和反饋用戶的屬性信息;IUserBiz負(fù)責(zé)用戶的行為,完成用戶信息的維護(hù)和變更。各位可能要說了,這個(gè)與我實(shí)際工作中用到的User類還是有差別的呀!別著急,我們先來看一看分拆成兩個(gè)接口怎么使用。OK,我們現(xiàn)在是面向接口編程,所以產(chǎn)生了這個(gè)UserInfo對(duì)象之后,當(dāng)然可以把它當(dāng)IUserBO接口使用。也可以當(dāng)IUserBiz接口使用,這要看你在什么地方使用了。要獲得用戶信息,就當(dāng)是IUserBO的實(shí)現(xiàn)類;要是希望維護(hù)用戶的信息,就把它當(dāng)作IUserBiz的實(shí)現(xiàn)類就成了,如代碼清單1-1所示。
圖1-2 職責(zé)劃分后的類圖
代碼清單1-1 分清職責(zé)后的代碼示例
......
IUserInfo userInfo = new UserInfo();
//我要賦值了,我就認(rèn)為它是一個(gè)純粹的BO
IUserBO userBO = (IUserBO)userInfo;
userBO.setPassword(""abc"");
//我要執(zhí)行動(dòng)作了,我就認(rèn)為是一個(gè)業(yè)務(wù)邏輯類
IUserBiz userBiz = (IUserBiz)userInfo;
userBiz.deleteUser();
......
確實(shí)可以如此,問題也解決了,但是我們來分析一下剛才的動(dòng)作,為什么要把一個(gè)接口拆分成兩個(gè)呢?其實(shí),在實(shí)際的使用中,我們更傾向于使用兩個(gè)不同的類或接口:一個(gè)是IUserBO,一個(gè)是IUserBiz,類圖如圖1-3所示。
以上我們把一個(gè)接口拆分成兩個(gè)接口的動(dòng)作,就是依賴了單一職責(zé)原則,那什么是單一職責(zé)原則呢?單一職責(zé)原則的定義是:應(yīng)該有且僅有一個(gè)原因引起類的變更。
1.2 絕殺技,打破你的傳統(tǒng)思維
解釋到這里,估計(jì)你已經(jīng)很不屑了,“切!這么簡(jiǎn)單的東西還要講?!”好,我們來講點(diǎn)復(fù)雜的。SRP的原話解釋是:
There should never be more than one reason for a class to change.
這句話初中生都能看懂,不多說,但是看懂是一碼事,實(shí)施就是另外一碼事了。上面講的例子很好理解,在實(shí)際項(xiàng)目中大家都已經(jīng)這么做了,那我們?cè)賮砜纯聪旅孢@個(gè)例子是否好理解。電話這玩意,是現(xiàn)代人都離不了,電話通話的時(shí)候有4個(gè)過程發(fā)生:撥號(hào)、通話、回應(yīng)、掛機(jī),那我們寫一個(gè)接口,其類圖如圖1-4所示。
我不是有意要冒犯IPhone的,同名純屬巧合,我們來看一個(gè)這個(gè)過程的代碼,如代碼清單1-2所示。
代碼清單1-2 電話過程
public interface IPhone {
//撥通電話
public void dial(String phoneNumber);
//通話
public void chat(Object o);
//通話完畢,掛電話
public void hangup();
}
實(shí)現(xiàn)類也比較簡(jiǎn)單,我就不再寫了,大家看看這個(gè)接口有沒有問題?我相信大部分的讀者都會(huì)說這個(gè)沒有問題呀,以前我就是這么做的呀,某某書上也是這么寫的呀,還有什么什么的源碼也是這么寫的!是的,這個(gè)接口接近于完美,看清楚了,是“接近”!單一職責(zé)原則要求一個(gè)接口或類只有一個(gè)原因引起變化,也就是一個(gè)接口或類只有一個(gè)職責(zé),它就負(fù)責(zé)一件事情,看看上面的接口只負(fù)責(zé)一件事情嗎?是只有一個(gè)原因引起變化嗎?好像不是!
IPhone這個(gè)接口可不是只有一個(gè)職責(zé),它包含了兩個(gè)職責(zé):一個(gè)是協(xié)議管理,一個(gè)是數(shù)據(jù)傳送。dial()和hangup()兩個(gè)方法實(shí)現(xiàn)的是協(xié)議管理,分別負(fù)責(zé)撥號(hào)接通和掛機(jī);chat()實(shí)現(xiàn)的是數(shù)據(jù)的傳送,把我們說的話轉(zhuǎn)換成模擬信號(hào)或數(shù)字信號(hào)傳遞到對(duì)方,然后再把對(duì)方傳遞過來的信號(hào)還原成我們聽得懂的語言。我們可以這樣考慮這個(gè)問題,協(xié)議接通的變化會(huì)引起這個(gè)接口或?qū)崿F(xiàn)類的變化嗎?會(huì)的!那數(shù)據(jù)傳送(想想看,電話不僅僅可以通話,還可以上網(wǎng))的變化會(huì)引起這個(gè)接口或?qū)崿F(xiàn)類的變化嗎?會(huì)的!那就很簡(jiǎn)單了,這里有兩個(gè)原因都引起了類的變化。這兩個(gè)職責(zé)會(huì)相互影響嗎?電話撥號(hào),我只要能接通就成,甭管是電信的還是網(wǎng)通的協(xié)議;電話連接后還關(guān)心傳遞的是什么數(shù)據(jù)嗎?通過這樣的分析,我們發(fā)現(xiàn)類圖上的IPhone接口包含了兩個(gè)職責(zé),而且這兩個(gè)職責(zé)的變化不相互影響,那就考慮拆分成兩個(gè)接口,其類圖如圖1-5所示。
這個(gè)類圖看上去有點(diǎn)復(fù)雜了,完全滿足了單一職責(zé)原則的要求,每個(gè)接口職責(zé)分明,結(jié)構(gòu)清晰,但是我相信你在設(shè)計(jì)的時(shí)候肯定不會(huì)采用這種方式,一個(gè)手機(jī)類要把ConnectionManager和DataTransfer組合在一塊才能使用。組合是一種強(qiáng)耦合關(guān)系,你和我都有共同的生命期,這樣的強(qiáng)耦合關(guān)系還不如使用接口實(shí)現(xiàn)的方式呢,而且還增加了類的復(fù)雜性,多了兩個(gè)類。經(jīng)過這樣的思考后,我們?cè)傩薷囊幌骂悎D,如圖1-6所示。
圖1-5職責(zé)分明的電話類圖
圖1-6 簡(jiǎn)潔清晰、職責(zé)分明的電話類圖
這樣的設(shè)計(jì)才是完美的,一個(gè)類實(shí)現(xiàn)了兩個(gè)接口,把兩個(gè)職責(zé)融合在一個(gè)類中。你會(huì)覺得這個(gè)Phone有兩個(gè)原因引起變化了呀,是的,但是別忘記了我們是面向接口編程,我們對(duì)外公布的是接口而不是實(shí)現(xiàn)類。而且,如果真要實(shí)現(xiàn)類的單一職責(zé),這個(gè)就必須使用上面的組合模式了,這會(huì)引起類間耦合過重、類的數(shù)量增加等問題,人為地增加了設(shè)計(jì)的復(fù)雜性。
通過上面的例子,我們來總結(jié)一下單一職責(zé)原則有什么好處:
q 類的復(fù)雜性降低,實(shí)現(xiàn)什么職責(zé)都有清晰明確的定義;
q 可讀性提高,復(fù)雜性降低,那當(dāng)然可讀性提高了;
q 可維護(hù)性提高,可讀性提高,那當(dāng)然更容易維護(hù)了;
q 變更引起的風(fēng)險(xiǎn)降低,變更是必不可少的,如果接口的單一職責(zé)做得好,一個(gè)接口修改只對(duì)相應(yīng)的實(shí)現(xiàn)類有影響,對(duì)其他的接口無影響,這對(duì)系統(tǒng)的擴(kuò)展性、維護(hù)性都有非常大的幫助。
看過電話這個(gè)例子后,是不是想反思一下了,我以前的設(shè)計(jì)是不是有點(diǎn)問題了?不,不是的,不要懷疑自己的技術(shù)能力,單一職責(zé)原則最難劃分的就是職責(zé)。一個(gè)職責(zé)一個(gè)接口,但問題是“職責(zé)”沒有一個(gè)量化的標(biāo)準(zhǔn),一個(gè)類到底要負(fù)責(zé)那些職責(zé)?這些職責(zé)該怎么細(xì)化?細(xì)化后是否都要有一個(gè)接口或類?這些都需要從實(shí)際的項(xiàng)目去考慮,從功能上來說,定義一個(gè)IPhone接口也沒有錯(cuò),實(shí)現(xiàn)了電話的功能,而且設(shè)計(jì)還很簡(jiǎn)單,僅僅一個(gè)接口一個(gè)實(shí)現(xiàn)類,實(shí)際的項(xiàng)目我想大家都會(huì)這么設(shè)計(jì)。項(xiàng)目要考慮可變因素和不可變因素,以及相關(guān)的收益成本比率,因此設(shè)計(jì)一個(gè)IPhone接口也可能是沒有錯(cuò)的。但是,如果純從“學(xué)究”理論上分析就有問題了,有兩個(gè)可以變化的原因放到了一個(gè)接口中,這就為以后的變化帶來了風(fēng)險(xiǎn)。如果以后模擬電話升級(jí)到數(shù)字電話,我們提供的接口IPhone是不是要修改了?接口修改對(duì)其他的Invoker類是不是有很大影響?
注意 單一職責(zé)原則提出了一個(gè)編寫程序的標(biāo)準(zhǔn),用“職責(zé)”或“變化原因”來衡量接口或類設(shè)計(jì)得是否優(yōu)良,但是“職責(zé)”和“變化原因”都是不可度量的,因項(xiàng)目而異,因環(huán)境而異。"