- 秒懂設(shè)計(jì)模式
- 劉韜
- 5989字
- 2021-07-09 10:30:51
第1章 初探

在這個(gè)計(jì)算機(jī)發(fā)展日新月異的時(shí)代,軟件產(chǎn)品不斷推陳出新、讓人應(yīng)接不暇,軟件需求更是變幻莫測(cè),難以捉摸。作為技術(shù)人員,我們?cè)谲浖_發(fā)過(guò)程中常常會(huì)遇到代碼重復(fù)的問(wèn)題,從而不得不對(duì)系統(tǒng)進(jìn)行大量改動(dòng),這不但帶來(lái)很多額外工作,而且會(huì)給產(chǎn)品帶來(lái)不必要的風(fēng)險(xiǎn)。因此,良好、穩(wěn)固的軟件架構(gòu)就顯得至關(guān)重要。設(shè)計(jì)模式正是為了解決這些問(wèn)題,它針對(duì)各種場(chǎng)景提供了適合的代碼模塊的復(fù)用及擴(kuò)展解決方案。
設(shè)計(jì)模式最早于1994年由Gang Of Four(四人小組)提出,并以面向?qū)ο笳Z(yǔ)言C++作為示例,如今已大量應(yīng)用于Java、C#等面向?qū)ο笳Z(yǔ)言所開發(fā)的程序中。其實(shí)設(shè)計(jì)模式和編程語(yǔ)言并不是密切相關(guān)的,因?yàn)榫幊陶Z(yǔ)言只是人與計(jì)算機(jī)溝通的媒介,它們可以用自己的方式去實(shí)現(xiàn)某種設(shè)計(jì)模式。從某種意義上講,設(shè)計(jì)模式并不是指某種具體的技術(shù),而更像是一種思想,一種格局。本書將以時(shí)下流行的面向?qū)ο缶幊陶Z(yǔ)言Java為例,對(duì)23種設(shè)計(jì)模式逐一拆解、分析。
在學(xué)習(xí)設(shè)計(jì)模式之前,我們先得搞清楚到底什么是面向?qū)ο?。我們生活的現(xiàn)實(shí)世界里充滿了各種對(duì)象,如大自然中的山川河流、花鳥魚蟲,抑或是現(xiàn)代文明中的高樓大廈、車水馬龍,我們每天都要面對(duì)它們,與它們溝通、互動(dòng),這是對(duì)面向?qū)ο笞詈?jiǎn)單的理解。為了將現(xiàn)實(shí)世界重現(xiàn)于計(jì)算機(jī)世界中,我們想了各種方法針對(duì)這些對(duì)象建立數(shù)字模型,但是理想很“豐滿”,而現(xiàn)實(shí)很“骨感”,我們永遠(yuǎn)無(wú)法包羅萬(wàn)象。人們?cè)凇霸煳铩钡倪^(guò)程中發(fā)現(xiàn),各種模型并非孤立存在的,它們之間有著千絲萬(wàn)縷的關(guān)聯(lián),于是便出現(xiàn)了面向?qū)ο笏赜械木幊谭椒?。我們利用封裝、繼承、多態(tài)的方式去建模,從而大量減少重復(fù)代碼、降低模塊間耦合,像拼積木一樣組裝了整個(gè)“世界”。這里提到的“封裝”“繼承”和“多態(tài)”便是面向?qū)ο蟮娜筇匦?,它們是掌握設(shè)計(jì)模式不可或缺的先決條件與理論基礎(chǔ),我們必須要對(duì)其進(jìn)行全面透徹的理解。
1.1 封裝
想要理解封裝,我們可以先觀察一下現(xiàn)實(shí)世界中的事物,比如膠囊對(duì)于各類混合藥物的封裝;錢包對(duì)于現(xiàn)金、身份證及銀行卡的封裝;計(jì)算機(jī)主機(jī)機(jī)箱對(duì)于主板、CPU及內(nèi)存等配件的封裝等。
由此可見,封裝在我們生活中隨處可見。我們舉一個(gè)現(xiàn)實(shí)生活中常見的例子。如圖1-1所示,注意餐盤中的可樂(lè)杯,其中的飲料是被裝在杯子里面的,杯子的最上面封上蓋子,只留有一個(gè)孔用于插吸管,這其實(shí)就是封裝。封裝隱藏了杯子內(nèi)部的飲料,也許還會(huì)有冰塊,而對(duì)于杯子外部來(lái)說(shuō)只留有一個(gè)“接口”用于訪問(wèn)。這樣的做法是否多此一舉?又會(huì)帶來(lái)什么好處呢?首先是方便、快捷,只有這樣我們才能拿著飲料杯四處行走,隨吸隨飲,而不至于把飲料灑得到處都是,因?yàn)榱闵⒌臄?shù)據(jù)缺乏集中管理,難以引用、讀取。其次是封裝后的可樂(lè)更加干凈、衛(wèi)生,可以防止外部的灰塵落入,杯子里面以關(guān)鍵字“private”聲明的可樂(lè)會(huì)成為內(nèi)部的私有化對(duì)象,因此能防止外部隨意訪問(wèn),避免造成數(shù)據(jù)污染。最后,對(duì)外暴露的吸管接口帶來(lái)了極大便利,顧客在喝可樂(lè)時(shí)根本不需要關(guān)心杯子的內(nèi)部對(duì)象和工作機(jī)制,如杯子中的冰塊如何讓可樂(lè)降溫、杯體內(nèi)部的氣壓如何變化、氣壓差又是如何導(dǎo)致可樂(lè)流出等實(shí)現(xiàn)細(xì)節(jié)對(duì)顧客完全是不可見的,留給顧客的操作其實(shí)非常簡(jiǎn)單,只需調(diào)用“吸”這個(gè)公有方法就可以喝到冰爽的可樂(lè)了。

圖1-1 飲料的封裝
我們?cè)賮?lái)分析一下對(duì)計(jì)算機(jī)主機(jī)的封裝,它必然需要一個(gè)機(jī)箱把各種配件封裝進(jìn)去,如主板、CPU、內(nèi)存、顯卡、硬盤等。一方面,機(jī)箱起到保護(hù)作用,防止異物(如老鼠、昆蟲等)進(jìn)入內(nèi)部而破壞電路;另一方面,機(jī)箱也不是完全封閉的,它一定對(duì)外預(yù)留有一些訪問(wèn)接口,如開機(jī)按鈕、USB接口等,這樣用戶才能夠使用計(jì)算機(jī),計(jì)算機(jī)主機(jī)的類結(jié)構(gòu)如圖1-2所示。

圖1-2 計(jì)算機(jī)主機(jī)的類結(jié)構(gòu)
封裝的概念在歷史發(fā)展中也非常多見,其實(shí)它就是隨著時(shí)間的推移對(duì)前人經(jīng)驗(yàn)和技術(shù)產(chǎn)物的逐漸堆疊和組合的結(jié)果。舉個(gè)例子,早期的槍設(shè)計(jì)得非常簡(jiǎn)陋,打一發(fā)子彈需要很長(zhǎng)時(shí)間去準(zhǔn)備,裝填時(shí)要先把火藥倒入槍管內(nèi),然后裝入鉛彈,最后用棍子戳實(shí)后才能發(fā)射;而下一次發(fā)射還要再重復(fù)這一過(guò)程,耗時(shí)費(fèi)力。為了解決這個(gè)問(wèn)題,人們開始了思考,既然彈藥裝填如此困難,那么不如把彈頭和火藥組合后封裝在彈殼里。這樣只要撞擊彈殼底部,彈頭就會(huì)被爆炸的火藥崩出去,裝入槍膛的子彈便可發(fā)出,如圖1-3所示。
從彈藥到子彈的發(fā)展其實(shí)就是對(duì)彈藥的“封裝”,因此大大提高了裝彈效率。其實(shí)一次裝一發(fā)子彈還是不夠高效,如果再進(jìn)一步,在子彈外再封裝一層彈夾的話則會(huì)更顯著地提升效率。我們可以定義一個(gè)數(shù)據(jù)結(jié)構(gòu)“?!眮?lái)模擬這個(gè)彈夾,保證最早壓入(push)的子彈最后彈出(pop),這就是棧結(jié)構(gòu)“先進(jìn)后出,后進(jìn)先出”的特點(diǎn)。如此一來(lái),子彈打完后只需更換彈夾就可以了。至此,封裝的層層堆疊又上了一個(gè)層次,在機(jī)槍被發(fā)明出來(lái)之后冷兵器時(shí)代就徹底結(jié)束了。

圖1-3 彈藥的發(fā)展
在Java編程語(yǔ)言中,一對(duì)大括號(hào)“{}”就是類的外殼、邊界,它能很好地把類的各種屬性及行為包裹起來(lái),將它們封裝在類內(nèi)部并固化成一個(gè)整體。封裝好的類如同一個(gè)黑匣子,外部無(wú)法看到內(nèi)部的構(gòu)造及運(yùn)轉(zhuǎn)機(jī)制,而只能訪問(wèn)其暴露出來(lái)的屬性或方法。需要注意的是,我們千萬(wàn)不要過(guò)度設(shè)計(jì)、過(guò)度封裝,更不要東拉西扯、亂攀親戚,比如把臺(tái)燈、輪子、茶杯等物品封裝在一起,或者在計(jì)算機(jī)主機(jī)里封裝一個(gè)算盤。如果把一些不相干的對(duì)象硬生生封裝在一起,就會(huì)使代碼變得莫名其妙,難于維護(hù)與管理,所謂“物極必反,過(guò)猶不及”,所以封裝一定要適度。
1.2 繼承
繼承是非常重要的面向?qū)ο筇匦?,如果沒(méi)有它,代碼量會(huì)變得非常龐大且難以維護(hù)、修改。繼承可以使父類的屬性和方法延續(xù)到子類中,這樣子類就不需要重復(fù)定義,并且子類可以通過(guò)重寫來(lái)修改繼承而來(lái)的方法實(shí)現(xiàn),或者通過(guò)追加達(dá)到屬性與功能擴(kuò)展的目的。從某種意義上講,如果說(shuō)類是對(duì)象的模板,那么父類(或超類)則可以被看作模板的模板。
生物一代一代延續(xù)是靠什么來(lái)保持父輩的特征呢?沒(méi)錯(cuò),答案就是遺傳基因DNA,如圖1-4所示。正所謂“龍生龍鳳生鳳,老鼠的兒子會(huì)打洞”,如果沒(méi)有這個(gè)遺傳機(jī)制,代碼量就會(huì)急劇增大,很多功能、資源都會(huì)出現(xiàn)重復(fù)定義的情況,這樣就會(huì)造成極大的冗余和資源的浪費(fèi),所以受自然界的啟發(fā),面向?qū)ο缶陀辛死^承機(jī)制。

圖1-4 生物的遺傳基因
舉個(gè)例子,兒子從父親那里繼承了一些東西,就不需要通過(guò)別的方式獲得了,如繼承家產(chǎn)。再舉個(gè)例子,我們知道,狗是人類忠實(shí)的朋友,它們?cè)谝蝗f(wàn)多年的進(jìn)化過(guò)程中不斷繁衍,再加上人類的培育,衍生出許多品種,如圖1-5所示。

圖1-5 犬類的繼承
基于圖1-5所示的繼承關(guān)系,我們思考一下如何用代碼來(lái)建模,倘若為每個(gè)犬類品種都定義一個(gè)類并封裝各自的屬性和方法,這顯然不行,因?yàn)轭愐欢鄤?shì)必會(huì)造成代碼泛濫。其實(shí),不管是什么犬類品種,它們都有某些共同的特征與行為,如吠叫行為等,所以我們需要把犬類共有的基因抽離出來(lái),并封裝到一個(gè)犬類祖先中以供后代繼承,請(qǐng)參看代碼清單1-1。
代碼清單1-1 犬類的祖先Dog
1. public class Dog {
2. protected String breeds;//品種
3. protected boolean sex;//性別
4. protected String color;//毛色
5. protected int age;//年齡
6.
7. public Dog(String breeds) {
8. this.age = 0; //初始化為0歲
9. this.breeds = breeds; //初始化犬類品種
10. }
11.
12. public void bark(){//吠叫
13. System.out.println("汪汪汪");
14. }
15.
16. public String getBreeds() {
17. return breeds;
18. }
19.
20. /*假設(shè)自出生后就不可以變種了,那么此處不應(yīng)暴露setBreeds方法
21. public void setBreeds(String breeds) {
22. this.breeds = breeds;
23. }
24. */
25. public boolean isSex() {
26. return sex;
27. }
28.
29. public void setSex(boolean sex) {
30. this.sex = sex;
31. }
32.
33. public String getColor() {
34. return color;
35. }
36.
37. public void setColor(String color) {
38. this.color = color;
39. }
40.
41. public int getAge() {
42. return age;
43. }
44.
45. public void setAge(int age) {
46. this.age = age;
47. }
48. }
如代碼清單1-1所示,我們?yōu)槿惗x了品種、性別、毛色、年齡這4個(gè)屬性,并且?guī)в邢鄳?yīng)的setter方法和getter方法。第12行的吠叫方法是犬類的共有行為,理所當(dāng)然能被子類繼承。需要注意的是,倘若我們把犬類屬性的訪問(wèn)權(quán)限由“protected”改為“private”,就意味著子類不能再直接訪問(wèn)這些屬性了,但這并無(wú)大礙,最終子類依舊可以通過(guò)繼承而來(lái)的并且聲明為“public”的getter方法和setter方法去間接訪問(wèn)它們。好了,接下來(lái)我們用子類哈士奇類來(lái)說(shuō)明如何繼承,請(qǐng)參看代碼清單1-2。
代碼清單1-2 哈士奇類Husky
1. public class Husky extends Dog {
2.
3. public Husky() {
4. super("哈士奇");
5. }
6.
7. public void sleighRide() {//拉雪橇
8. System.out.println("拉雪橇");
9. }
10.
11. }
如代碼清單1-2所示,為了延續(xù)父類的基因,哈士奇類在第一行的類定義后用“extends”關(guān)鍵字聲明了對(duì)父類Dog的繼承。第4行以“super”關(guān)鍵字調(diào)用了父類的構(gòu)造方法,并初始化了狗的品種breeds為“哈士奇”,當(dāng)然年齡一并會(huì)被父類初始化為0歲。我們可以看到哈士奇類的代碼已經(jīng)變得特別簡(jiǎn)單了,既沒(méi)有定義任何getter方法或setter方法,又沒(méi)有定義吠叫方法,而當(dāng)我們調(diào)用這些方法時(shí)卻能神奇般地得到結(jié)果,這是因?yàn)樗^承了父類的方法,不需要我們重新定義。只是能夠單單地繼承父類是不夠的,哈士奇類還應(yīng)該有自己的特色,這就要增加其自己的屬性、方法,在代碼第7行中我們?cè)黾恿斯科骖愃赜械摹袄┣痢毙袨?,這是父類所不具有的。除此之外,哈士奇吠叫起來(lái)比較特殊,這可能是基因突變或者是返祖現(xiàn)象所致,這時(shí)我們甚至可以重寫吠叫方法以讓它發(fā)出狼的叫聲。其他子類的繼承也可以各盡其能,比如貴賓犬可以作揖,藏獒可以看家護(hù)院等,讀者可以自己發(fā)揮。總之,繼承的目的并不只是全盤照搬,而是可以基于父類的基因靈活擴(kuò)展。
擴(kuò)展閱讀
我們知道任何類都有一個(gè)toString()方法,但我們根本沒(méi)有聲明它,這是為什么呢?其實(shí)這是從Object類繼承的方法,因?yàn)镺bject是一切類的祖先類。
1.3 多態(tài)
眾所周知,在我們創(chuàng)建對(duì)象的時(shí)候通常會(huì)再定義一個(gè)引用指向它,以便后續(xù)進(jìn)行對(duì)象操作,而這個(gè)引用的類型則決定著其能夠指向哪些對(duì)象,用犬類定義的引用絕不能指向貓類對(duì)象,所以對(duì)于父類定義的引用只能指向本類或者其子類實(shí)例化而來(lái)的對(duì)象,這就是一種多態(tài)。除此之外,還有其他形式的多態(tài),例如抽象類引用指向子類對(duì)象,接口引用指向?qū)崿F(xiàn)類的對(duì)象,其本質(zhì)上都別無(wú)二致。
我們繼續(xù)以1.2節(jié)中的犬類繼承為例。如果以犬類Dog作為父類,那么哈士奇、貴賓犬、藏獒、吉娃娃等都可以作為其子類。如果我們定義犬類引用dog,那么它就可以指向犬類的對(duì)象,或者其任意子類的對(duì)象,也就是“哈士奇是犬類,藏獒是犬類……”。下面我們用代碼來(lái)表示,請(qǐng)參看代碼清單1-3。
代碼清單1-3 犬類多態(tài)構(gòu)造示例
1. Dog dog; //定義父類引用
2. dog = new Dog();//父類引用指向父類對(duì)象(狗是犬類)
3. dog = new Husky()//父類引用指向子類對(duì)象(哈士奇是犬類)
4.
5. Husky husky = new Dog();//錯(cuò)誤:子類引用指向父類對(duì)象(犬類是哈士奇)
如代碼清單1-3所示,前3行沒(méi)有任何問(wèn)題,犬類引用可以指向犬類的對(duì)象,也可以指向哈士奇類的對(duì)象,這讓dog引用變得更加靈活、多變,可以引用任何本類或子類的對(duì)象。然而第5行代碼則會(huì)出錯(cuò),因?yàn)樽尮科骖惖囊弥赶蛉怐og的對(duì)象就行不通了,這就好像說(shuō)“犬類就是哈士奇”一樣,邏輯不通。
再進(jìn)一步講,多態(tài)其實(shí)是利用了繼承(或接口實(shí)現(xiàn))這個(gè)特性體現(xiàn)出來(lái)的另一番景象。我們以食物舉例,中華美食博大精深,菜品眾多且色香味俱全,這都離不開各種各樣的食材,如圖1-6所示。

圖1-6 有機(jī)食物的多態(tài)性
雖然食材形態(tài)各異,但是萬(wàn)變不離其宗,它們都是自然界生長(zhǎng)出來(lái)的有機(jī)生物。而作為人類,我們可以食用哪些食物呢?顯而易見,人類只可以食用有機(jī)食物,對(duì)于金屬、塑料等是不能消化的。所以正如圖1-7所展示的那樣,人類所能接受的食物對(duì)象可以是番茄、蘋果、牛肉等有機(jī)食物的多形態(tài)表現(xiàn),而不能是金屬類物質(zhì)。

圖1-7 人類與食物的關(guān)系類結(jié)構(gòu)
也許有人會(huì)提出疑問(wèn),全部用Object類作為引用不是更加靈活,多態(tài)性更加豐富嗎?其實(shí),任何事物都有兩面性,一方面帶來(lái)了靈活性,而另一方面造成了破壞性。
1.4 計(jì)算機(jī)與外設(shè)
為了更透徹地理解面向?qū)ο蟮奶匦?,以及設(shè)計(jì)模式如何巧妙利用面向?qū)ο蟮奶匦詠?lái)組織各種模塊協(xié)同工作,我們就以計(jì)算機(jī)這個(gè)既形象又貼切的例子來(lái)切入實(shí)戰(zhàn)部分。如圖1-8所示,相信很多年輕的讀者都沒(méi)有見過(guò)這種早期的個(gè)人計(jì)算機(jī),它的鍵盤、主機(jī)和顯示器等都是集成為一體的。

圖1-8 老式計(jì)算機(jī)
越是老式的計(jì)算機(jī),其集成度越高,甚至把所有配件都一體化,配件之間的耦合度極高,難以拆分。這種過(guò)度封裝的計(jì)算機(jī)為什么會(huì)退出歷史舞臺(tái)呢?試想,某天顯示器壞了,我們只能把整個(gè)機(jī)器拆開更換顯示器。如果顯示器是焊接在主板上的,情況就更糟糕了。缺少接口的設(shè)計(jì)造成了極高的耦合度,而更糟的是,如果這種顯示器已經(jīng)停產(chǎn)了,那么結(jié)果只能是整機(jī)換新。
為解決這個(gè)問(wèn)題,設(shè)計(jì)人員提出了模塊化的概念,各種外設(shè)如雨后春筍般涌現(xiàn),如鼠標(biāo)、鍵盤、攝像頭、打印機(jī)、外接硬盤……但這時(shí)又出現(xiàn)一個(gè)問(wèn)題,如果每種設(shè)備都有一種接口,那么計(jì)算機(jī)主機(jī)上得有多少種接口?這些接口包括串口、并口、PS2接口……接口泛濫將是一場(chǎng)災(zāi)難,采用標(biāo)準(zhǔn)化的接口勢(shì)在必行,于是便有了現(xiàn)在的USB接口。USB提供了一種接口標(biāo)準(zhǔn):電壓5V,雙工數(shù)據(jù)傳輸,最重要的是其物理形態(tài)上的統(tǒng)一規(guī)范,只要是USB標(biāo)準(zhǔn),設(shè)備就可以進(jìn)行接駁,最終計(jì)算機(jī)發(fā)展成為圖1-9所示的樣子。

圖1-9 現(xiàn)代計(jì)算機(jī)
我們每天都在接觸計(jì)算機(jī),對(duì)于這種設(shè)計(jì)可能從未思考過(guò)。為了便于理解,我們讓計(jì)算機(jī)和各種外設(shè)鮮活起來(lái),下面是它們之間展開的一場(chǎng)精彩對(duì)話,其中的角色包括一臺(tái)計(jì)算機(jī),一個(gè)USB接口,還有幾個(gè)USB設(shè)備,故事就這樣開始了。
計(jì)算機(jī):“我宣布,從現(xiàn)在開始USB接口晉升為我的秘書,我只接收它傳遞過(guò)來(lái)的數(shù)據(jù),誰(shuí)要找我溝通必須通過(guò)它?!?/span>
USB接口:“我不關(guān)心要接駁我的設(shè)備是什么,但我規(guī)定你必須實(shí)現(xiàn)我定義的getData()這個(gè)方法,但具體怎樣實(shí)現(xiàn)我不管,總之我會(huì)調(diào)用你的這個(gè)方法把數(shù)據(jù)讀取過(guò)來(lái)?!?/span>
USB鍵盤:“我有readData(data Data)這個(gè)方法,我已經(jīng)實(shí)現(xiàn)好了,傳過(guò)去的是用戶輸入的字符。”
USB鼠標(biāo):“我也一樣,但傳過(guò)去的是鼠標(biāo)移動(dòng)或點(diǎn)擊數(shù)據(jù)?!?/span>
USB攝像頭:“沒(méi)錯(cuò),我也實(shí)現(xiàn)了這個(gè)方法,只是我的數(shù)據(jù)是視頻流相關(guān)的?!?/span>
USB接口:“不管你們是什么類型的數(shù)據(jù),只要傳過(guò)來(lái)轉(zhuǎn)換成Data就行了,我接收你們的接駁請(qǐng)求,除了PS2鼠標(biāo)。”
PS2鼠標(biāo):“@計(jì)算機(jī),老大,這怎么辦?你找來(lái)的這個(gè)USB接口太霸道了,我們根本無(wú)法溝通,你們不能尊重一下老人嗎?”
計(jì)算機(jī):“你自己想辦法,要順應(yīng)時(shí)代潮流,與時(shí)俱進(jìn)。”
PS2鼠標(biāo):……
通過(guò)這場(chǎng)對(duì)話,我們對(duì)計(jì)算機(jī)和外設(shè)以及它們之間的關(guān)系有了更深刻的認(rèn)識(shí)。計(jì)算機(jī)中裝了一個(gè)USB接口,這就是“封裝”,而鍵盤、鼠標(biāo)及攝像頭都是USB接口的實(shí)現(xiàn)類,從廣義上理解這就是一種“繼承”,所以計(jì)算機(jī)的USB接口就能接駁各種各樣的USB設(shè)備,這就是“多態(tài)”。我們來(lái)看它們的類結(jié)構(gòu),如圖1-10所示。

圖1-10 現(xiàn)代計(jì)算機(jī)的類結(jié)構(gòu)
通過(guò)對(duì)計(jì)算機(jī)接口的抽象化、標(biāo)準(zhǔn)化,我們對(duì)各個(gè)模塊重新分類、規(guī)劃,并合理封裝,最終實(shí)現(xiàn)計(jì)算機(jī)與外設(shè)的徹底解耦。多態(tài)化的外設(shè)使計(jì)算機(jī)功能更加強(qiáng)大、靈活、可擴(kuò)展、可替換。其實(shí)這就是設(shè)計(jì)模式中非常重要的一種“策略模式”,接口的定義是解決耦合問(wèn)題的關(guān)鍵所在。但對(duì)于一些老舊的接口設(shè)備模塊,我們暫時(shí)還無(wú)法使用,正如同上面故事里那個(gè)可憐的PS2鼠標(biāo)。
我們都知道有一種設(shè)備叫轉(zhuǎn)換器,它能輕松地將老舊的接口設(shè)備調(diào)制適配到新的接口,以達(dá)到兼容的目的,這就是“適配器模式”。這些設(shè)計(jì)模式后續(xù)都會(huì)被講到,我們會(huì)由淺入深、一步一個(gè)腳印地逐個(gè)解析。讀者一定要邊學(xué)邊思考,理論一定要與實(shí)踐結(jié)合才能舉一反三、融會(huì)貫通,如此才能合理有效地利用設(shè)計(jì)模式設(shè)計(jì)出更加優(yōu)雅、健壯、靈活的應(yīng)用程序。
- R語(yǔ)言經(jīng)典實(shí)例(原書第2版)
- 軟件界面交互設(shè)計(jì)基礎(chǔ)
- 秒懂設(shè)計(jì)模式
- Node.js全程實(shí)例
- Learning AngularJS for .NET Developers
- iOS自動(dòng)化測(cè)試實(shí)戰(zhàn):基于Appium、Python與Pytest
- INSTANT Yii 1.1 Application Development Starter
- 細(xì)說(shuō)Python編程:從入門到科學(xué)計(jì)算
- Scala編程(第5版)
- Mastering Apache Storm
- OpenCV with Python Blueprints
- INSTANT Premium Drupal Themes
- ServiceDesk Plus 8.x Essentials
- Learning IBM Bluemix
- 代碼揭秘