第七部分 ? ? ?算 ?法 ?封 ?裝
第18章 ? ? ?模 ?板 ?方 ?法
何為模板方法模式
模板方法模式是面向?qū)ο筌浖O(shè)計(jì)中一種非常簡單的設(shè)計(jì)模式。其基本思想是在抽象類的一個(gè)方法中定義“標(biāo)準(zhǔn)”算法背伴。在這個(gè)方法中調(diào)用的基本操作應(yīng)由子類重載予以實(shí)現(xiàn)沸毁。這個(gè)方法被稱為“模板”,因?yàn)榉椒ǘx的算法缺少一些特有的操作傻寂。抽象類定義模板息尺,子類重載基本操作以提供獨(dú)特操作供模板方法調(diào)用。
模板方法模式:定義一個(gè)操作中算法的骨架疾掰,而將一些步驟延遲到子類中搂誉。模板方法使子類可以重定義算法的某些特定步驟而不改變?cè)撍惴ǖ慕Y(jié)構(gòu)。
何時(shí)使用模板方法
- ?需要一次性實(shí)現(xiàn)算法的不變部分静檬,并將可變的行為留給子類來實(shí)現(xiàn)勒葱。
- ?子類的共同行為應(yīng)該被提取出來放到公共類中,以避免代碼重復(fù)“褪粒現(xiàn)有代碼的差別應(yīng)該被分離為新的操作凛虽。然后用一個(gè)調(diào)用這些新操作的模板方法來替換這些不同的代碼。
- 需要控制子類的擴(kuò)展广恢】可以定義一個(gè)在特定點(diǎn)調(diào)用“鉤子”操作的模板方法。子類可以通過對(duì)鉤子操作的實(shí)現(xiàn)在這些點(diǎn)擴(kuò)展功能。
鉤子操作給出了默認(rèn)行為至非,子類可對(duì)其擴(kuò)展钠署。默認(rèn)行為通常什么都不做。子類可以重載這個(gè)方法荒椭,為模板算法提供附加的操作谐鼎。模板方法模式中的控制結(jié)構(gòu)流程是倒轉(zhuǎn)的,因?yàn)楦割惖哪0宸椒ㄕ{(diào)用其子類的操作趣惠,而不是子類調(diào)用父類的操作狸棍。
模板方法會(huì)調(diào)用5種類型的操作:
- 對(duì)具體類或客戶端類的具體操作;
- 對(duì)抽象類的具體操作味悄;
- 抽象操作草戈;
- 工廠方法;
- 鉤子操作侍瑟。
模板方法與委托方法的比較
模板方法和委托模式(也叫適配器模式唐片,見第8章)常見于cocoa touch 框架。它們對(duì)框架類設(shè)計(jì)來說是非常自然的選擇涨颜。為什么呢费韭?用戶應(yīng)用程序可以復(fù)用(或擴(kuò)展)框架類,而且框架類在設(shè)計(jì)時(shí)不會(huì)知道什么樣的類會(huì)使用它們庭瑰⌒浅郑可是對(duì)于特定的軟件設(shè)計(jì)問題應(yīng)該使用哪一個(gè)模式呢?以下是簡要的指導(dǎo)方針见擦。
模板方法: 父類定義一個(gè)一般算法钉汗,但缺少某些特定/可選的信息或算法,它通過這些缺少的信息或算法起到一個(gè)算法“食譜”的作用鲤屡;缺少的信息由子類通過繼承來提供损痰。
委托模式(適配器):委托與預(yù)先定義好的委托接口一起定義一個(gè)特定算法;特定算法由任何對(duì)象通過對(duì)象組合來提供酒来。
在cocoa touch框架中使用模板方法
在框架設(shè)計(jì)中卢未,模板方法模式相當(dāng)常見。模板方法是代碼復(fù)用的基礎(chǔ)技術(shù)堰汉。通過它辽社,框架的設(shè)計(jì)師可以把算法中應(yīng)用程序相關(guān)的元素留給應(yīng)用程序去實(shí)現(xiàn)。模板方法是抽出共同行為放入框架類中的手段翘鸭。這一方式有助于提高可擴(kuò)展性與可復(fù)用性滴铅,而維持各種累到這些框架類,雖然不如delegation那么常見就乓。
總結(jié):?
模板方法模式是代碼復(fù)用的一項(xiàng)基本技術(shù)汉匙。模板方法在框架類設(shè)計(jì)中非常重要拱烁,因?yàn)樗浅槌龉餐袨榉湃肟蚣茴愔械氖侄巍?/p>
下一章將討論另一種把對(duì)象中的算法封裝成各種策略的方式。
第 ?19 ? 章 ? ? ?策 ? ? 略
面向?qū)ο筌浖O(shè)計(jì)中噩翠,我們可以把相關(guān)算法分離為不同的類戏自,成為策略。與這種做法有關(guān)的一種設(shè)計(jì)模式稱為策略模式伤锚。
何為策略模式
策略模式中的一個(gè)關(guān)鍵角色是策略類擅笔,它為所有支持的或相關(guān)的算法聲明了一個(gè)共同接口。另外屯援,還有使用策略接口來實(shí)現(xiàn)相關(guān)算法的具體策略類猛们。場景(context)類的對(duì)象配置有一個(gè)具體策略對(duì)象的實(shí)例,場景對(duì)象使用策略接口調(diào)用由具體策略類定義的算法玄呛。
策略模式:定義一系列算法阅懦,把它們一個(gè)個(gè)封裝起來和二,并且使它們可相互替換徘铝。本模式使得算法可獨(dú)立于使用它的客戶而變化。
模型-視圖-控制器中的策略模式
模型-視圖-控制器模式中惯吕,控制器決定視圖對(duì)模型數(shù)據(jù)進(jìn)行顯示的時(shí)機(jī)和內(nèi)容惕它。視圖本身知道如何繪圖,但需要控制器告訴它要顯示的內(nèi)容废登。同一個(gè)視圖如果與不同的控制器合作淹魄,數(shù)據(jù)的輸出格式可能一樣,但數(shù)據(jù)的類型和格式可能隨不同控制器的不同輸出而不同堡距。因此這種情況下的控制器是視圖的策略甲锡。
何時(shí)使用策略模式
- 一個(gè)類在其操作中使用多個(gè)條件語句來定義許多行為。我們可以把相關(guān)的條件分支移到它們自己的策略類中羽戒。
- 需要算法的各種變體缤沦。
- 需要避免把復(fù)雜的、與算法相關(guān)的數(shù)據(jù)結(jié)構(gòu)暴露給客戶端易稠。
總結(jié): ?
本章討論了策略模式的概念以及如何應(yīng)用這個(gè)模式讓客戶(場景)類使用相關(guān)算法的各種變體缸废,為定制的UITextField實(shí)現(xiàn)輸入驗(yàn)證器的例子,示范了各種驗(yàn)證器如何更換定制的UITextField的“內(nèi)容”驶社。策略模式與裝飾模式有些相似企量。裝飾器從外部擴(kuò)展對(duì)象的行為,而各種策略則被封裝在對(duì)象之中亡电。所以說裝飾器改變對(duì)象的“外表”而策略改變對(duì)象的“內(nèi)容”届巩。
下一章將討論與算法封裝有關(guān)的另一種模式。封裝的算法主要用于推遲命令對(duì)象的執(zhí)行份乒。
第 20 章 ? ?命 ? 令
何為命令模式
命令對(duì)象封裝了如何對(duì)目標(biāo)執(zhí)行指令的信息恕汇,因此客戶端或調(diào)用者不必了解目標(biāo)的任何細(xì)節(jié)零酪,卻仍可以對(duì)它執(zhí)行任何已有的操作。通過把請(qǐng)求封裝成對(duì)象拇勃,客戶端可以把它參數(shù)化并置入隊(duì)列或日志中四苇,也能夠支持可撤銷的操作。命令對(duì)象將一個(gè)或多個(gè)動(dòng)作綁定到特定的接收器方咆。命令模式消除了作為對(duì)象的動(dòng)作和執(zhí)行它的接收器之間的綁定月腋。
命令模式:將請(qǐng)求封裝為一個(gè)對(duì)象,從而可用不同的請(qǐng)求對(duì)客戶進(jìn)行參數(shù)化瓣赂,對(duì)請(qǐng)求排隊(duì)或記錄請(qǐng)求日志榆骚,以及支持可撤銷的操作。
何時(shí)使用命令模式
- ?想讓應(yīng)用程序支持撤銷與恢復(fù)煌集。
- ?想用對(duì)象參數(shù)化一個(gè)動(dòng)作以執(zhí)行操作妓肢,并用不同命令對(duì)象來代替回調(diào)函數(shù)。
- ?想要在不同時(shí)刻對(duì)請(qǐng)求進(jìn)行指定苫纤、排列和執(zhí)行碉钠。
- 想記錄修改日志,這樣在系統(tǒng)故障時(shí)卷拘,這些修改可在后來重做一遍喊废。
- ?想讓系統(tǒng)支持事務(wù),事務(wù)封裝了對(duì)數(shù)據(jù)的一系列修改栗弟。事務(wù)可以建模為命令對(duì)象污筷。
命令還能做什么
命令模式允許封裝在命令對(duì)象中的可執(zhí)行指令。這使得在實(shí)現(xiàn)撤銷和恢復(fù)基礎(chǔ)設(shè)施的時(shí)候自然會(huì)選擇這個(gè)模式乍赫。但這個(gè)模式的用途不只如此瓣蛀。命令對(duì)象的另一個(gè)為人熟知的應(yīng)用是推遲調(diào)用器的執(zhí)行。調(diào)用器可以是菜單項(xiàng)或按鈕雷厂。使用命令對(duì)象連結(jié)不同對(duì)象之間的操作相當(dāng)常見惋增,比如,單擊視圖控制器中的按鈕罗侯,可以執(zhí)行一個(gè)命令對(duì)象器腋,對(duì)另一個(gè)視圖控制器進(jìn)行某些操作。命令對(duì)象隱藏了與這些操作有關(guān)的所有細(xì)節(jié)钩杰。
從本章的實(shí)例項(xiàng)目中纫塌,讀者還可以發(fā)現(xiàn)另外幾個(gè)command類,它們使用touchpainter中的其他部分讲弄,有著不同的用途措左。
總結(jié):
本章介紹了命令模式,以及如何在OC中實(shí)現(xiàn)這一模式避除。我們?yōu)門ouchPainter應(yīng)用實(shí)現(xiàn)了一個(gè)撤銷基礎(chǔ)設(shè)施怎披,這樣用戶就可以撤銷和恢復(fù)屏幕上所畫的線條和點(diǎn)胸嘁。我們也講解了CocoaTouch框架如何用不同的調(diào)用和撤銷/恢復(fù)策略實(shí)現(xiàn)這個(gè)模式,讓它能夠應(yīng)用到任何iOS應(yīng)用程序之中凉逛。
消除應(yīng)用程序中命令性宏、調(diào)用器、接收器和客戶端的耦合状飞,其好處顯而易見毫胜。如果特定的命令需要在實(shí)現(xiàn)中修改,那么其他組織中的大部分都不受影響诬辈。而且添加新的命令類非常容易酵使,因?yàn)椴槐貫榇诵薷囊延械念悺?/p>
有關(guān)算法封裝的這個(gè)部分到此結(jié)束了。下一個(gè)部分將討論幾個(gè)與性能和對(duì)象訪問有關(guān)的設(shè)計(jì)模式焙糟。
第八部分 ? ?性能 與 對(duì)象訪問
第21章 ? 享 ?元
何為享元模式
實(shí)現(xiàn)享元模式需要兩個(gè)關(guān)鍵組件口渔,通常是可共享的享元對(duì)象和保存它們的池。某種中央對(duì)象維護(hù)這個(gè)池穿撮,并從它返回適當(dāng)?shù)膶?shí)例缺脉。
何時(shí)使用享元模式
- ?應(yīng)用程序使用很多對(duì)象;
- ?在內(nèi)存中保存對(duì)象會(huì)影響內(nèi)存性能混巧;
- ?對(duì)象的多數(shù)特有狀態(tài)(外在狀態(tài))可以放到外部而輕量化枪向;
- ?移除了外在狀態(tài)之后勤揩,可以用較少的共享對(duì)象不能替代原來的那組對(duì)象咧党;
?- ?應(yīng)用程序不依賴對(duì)象標(biāo)識(shí),因?yàn)楣蚕韺?duì)象不能提供唯一的標(biāo)識(shí)陨亡。
通過享元對(duì)象能夠節(jié)省的空間傍衡,取決于幾個(gè)因素:
- ?通過共享減少的對(duì)象總數(shù);
- ?每個(gè)對(duì)象中內(nèi)在狀態(tài)的數(shù)量负蠕;(即蛙埂,可共享的狀態(tài))
- ?外在狀態(tài)是計(jì)算出來的還是保存的。
然而遮糖,對(duì)享元對(duì)象外在狀態(tài)的傳遞、查找和計(jì)算,可能產(chǎn)生運(yùn)行時(shí)的開銷涯肩,尤其在外在狀態(tài)原本是作為內(nèi)在狀態(tài)來保存的時(shí)候溺职。當(dāng)享元的共享越來越多時(shí),空間的節(jié)省會(huì)抵消這些開銷赛不。共享的享元越多惩嘉,節(jié)省的存儲(chǔ)就越多。節(jié)省直接跟共享的狀態(tài)相關(guān)踢故。如果對(duì)象有大量內(nèi)在和外在狀態(tài)文黎,外在狀態(tài)又能夠計(jì)算出來而不用存儲(chǔ)的時(shí)候惹苗,就能節(jié)省最大的空間。這樣我們以兩種方式節(jié)省了存儲(chǔ)空間:共享減少了內(nèi)在狀態(tài)的開銷耸峭,通過犧牲計(jì)算時(shí)間又節(jié)省了外在狀態(tài)的存儲(chǔ)空間桩蓉。
總結(jié):?
分享是人類的美德。分享相同的資源以執(zhí)行任務(wù)劳闹,可能比使用個(gè)人的資源完成同樣的事情更加高效触机。本章,我們?cè)O(shè)計(jì)了一個(gè)可以在屏幕上顯示500多朵花的程序玷或,而只用了6個(gè)不同花朵圖案的實(shí)例儡首。這些不同的花朵實(shí)例,把一些與眾不同的可被標(biāo)識(shí)的信息去掉偏友,只剩下顯示花朵圖案的基本操作蔬胯。在請(qǐng)求特定的花朵的時(shí)候,客戶端需要向花朵實(shí)例提供某些與眾不同的信息(外在狀態(tài))位他,讓它使用這些信息繪制一朵與眾不同的花氛濒。不用享元模式的話,要在屏幕上畫多少朵花鹅髓,程序就需要實(shí)例化多少個(gè)UIImageView舞竿。經(jīng)過精心的設(shè)計(jì),享元模式可以通過共享一部分必需的對(duì)象窿冯,來節(jié)省大量的內(nèi)存骗奖。
在下一章將介紹另一種設(shè)計(jì)模式,它通過把操作推遲給代理對(duì)象來提升對(duì)象訪問醒串。
第22章 ? ? ? 代 ? ?理
何為代理模式:
有以下幾種代理:
- ?遠(yuǎn)程代理(remote ?proxy) ?為位于不同地址空間或網(wǎng)絡(luò)上的對(duì)象提供本地代表执桌;
- ?虛擬代理(virtual ?proxy) 根據(jù)需要?jiǎng)?chuàng)建重型對(duì)象;
- ?保護(hù)代理(protection ?proxy) 根據(jù)各自訪問權(quán)限控制對(duì)原對(duì)象的訪問芜赌;
- ?智能引用代理(smart-reference ?proxy) 通過對(duì)真正對(duì)象的引用進(jìn)行計(jì)數(shù)來管理內(nèi)存仰挣。也用于鎖定真正對(duì)象,讓其他對(duì)象不能對(duì)其進(jìn)行修改缠沈。
代理模式: 為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問膘壶。
何時(shí)使用代理模式
- ?需要一個(gè)遠(yuǎn)程代理,為位于不同地址空間或網(wǎng)絡(luò)中的對(duì)象提供本地代表洲愤;
- ?需要一個(gè)虛擬代理颓芭,來根據(jù)要求;
- ?需要一個(gè)保護(hù)代理禽篱,來根據(jù)不同訪問權(quán)限控制對(duì)原對(duì)象的訪問畜伐;
- ?需要一個(gè)智能引用代理,通過對(duì)實(shí)體對(duì)象的引用進(jìn)行計(jì)數(shù)來管理內(nèi)存躺率。也能用于鎖定實(shí)體對(duì)象玛界,讓其他對(duì)象不能修改它万矾。
總結(jié): ?
在iOS應(yīng)用開發(fā)中,總是要關(guān)注內(nèi)存的使用量慎框。不論應(yīng)用程序運(yùn)行在何種iOS設(shè)備上良狈,出于性能的考慮,總是推薦懶加載技術(shù)笨枯。如果大開銷的對(duì)象在收到請(qǐng)求之前不需要加載薪丁,則可通過虛擬代理向客戶端提供某些輕量的信息。
下一個(gè)部分將介紹另一種設(shè)計(jì)模式馅精,它會(huì)對(duì)對(duì)象狀態(tài)的保存過程進(jìn)行抽象严嗜。
第九部分 ? ? 對(duì)象狀態(tài)
第23章 ? ? 備忘錄
備忘錄模式: 在不破壞封裝的前提下,捕獲一個(gè)對(duì)象的內(nèi)部狀態(tài)洲敢,并在該對(duì)象之外保存這個(gè)狀態(tài)漫玄。這樣以后就將該對(duì)象恢復(fù)到原先保存的狀態(tài)。
何時(shí)使用備忘錄模式
當(dāng)同時(shí)滿足以下兩個(gè)條件時(shí)压彭,應(yīng)該考慮使用這一模式:
- ?需要保存一個(gè)對(duì)象(或某部分)在某一個(gè)時(shí)刻的狀態(tài)睦优,這樣以后就可以恢復(fù)到先前的狀態(tài);
- ?用于獲取狀態(tài)的接口會(huì)暴露實(shí)現(xiàn)的細(xì)節(jié)壮不,需要將其隱藏起來汗盘。
總結(jié):
本章討論了備忘錄模式概念,并通過touchpainter實(shí)例應(yīng)用询一,示范了如何將這一模式應(yīng)用到iOS應(yīng)用的開發(fā)中隐孽。通過保存對(duì)scribble對(duì)象內(nèi)部狀態(tài)的小修改的一個(gè)列表,scribblememento也能夠被復(fù)用于實(shí)現(xiàn)撤銷與恢復(fù)操作家凯。只保存了對(duì)scribble的小修改的scribblememento對(duì)象列表缓醋,可用于在網(wǎng)絡(luò)上共享線條。這樣共享相同繪圖會(huì)話的遠(yuǎn)程用戶绊诲,就能看到模擬的遠(yuǎn)程繪圖,一次畫一條線褪贵。
到這里本書中介紹設(shè)計(jì)模式的所有章節(jié)就都結(jié)束了〉嘀現(xiàn)在,讀者應(yīng)該能夠在實(shí)際項(xiàng)目中自由應(yīng)用這些設(shè)計(jì)模式了脆丁。