第二部分? ? 對? 象? 創(chuàng)? 建
第3章 ? 原 ?型
原型摸式是一種非常簡單的設(shè)計模式楣导。使用原型實例指定創(chuàng)建對象的種類,并通過復制這個原型創(chuàng)建新的對象。
在以下情形,會考慮使用原型模式悯舟。
- ?需要創(chuàng)建的對象應獨立于其類型與創(chuàng)建方式
- ?要實例化的類是在運行時決定的。
- ?不想要與產(chǎn)品層次相對應的工廠層次砸民。
- ?不同類的實例間的差異僅是狀態(tài)的若干組合抵怎。因此復制相應數(shù)量的原型比手工實例化更加方便。
- ?類不容易創(chuàng)建岭参,比如每個組件可把其他組件作為子節(jié)點的組合對象反惕。復制已有的組合對象并對副本進行修改會更加容易。
此模式的最低限度是生成對象的真實副本冗荸,以用作用一個環(huán)境下其他相關(guān)事物的基礎(chǔ)(原型)。
?淺復制與深復制
如果對象有個指針型成員變量指向內(nèi)存中的某個資源利耍,那么如何復制這個對象呢蚌本?你會只是復制指針的值傳給副本的新對象嗎?指針只是存儲內(nèi)存中資源地址的占位符隘梨。在復制操作中程癌,如果只是將指針復制給新對象,那么底層的資源實際上仍然由兩個實例在共享轴猎。所以只復制了指針值而不是實際資源嵌莉,這稱為淺復制。
深復制捻脖,是指不僅復制指針值锐峭,還復制指針所指向的資源。
使用Cocoa Touch框架中的對象復制
Cocoa Touch 框架為NSObject的派生類提供了實現(xiàn)深復制的協(xié)議可婶。NSObject的子類需要實現(xiàn)NSCopying協(xié)議及其方法—— (id)copyWithZone:(NSZone *)zone沿癞。 ? ?NSObject有一個實例方法叫做(id)copy。默認的copy方法調(diào)用[self ?copyWithZone:nil].對于采納了NSCopying協(xié)議的子類矛渴,而要實現(xiàn)這個方法椎扬,否則將引發(fā)異常。iOS中這個方法保持新的副本對象具温,然后將其返回蚕涤。此方法的調(diào)用者要負責釋放返回的對象。
總結(jié):原型模式是用于對象創(chuàng)建的非常簡單的模式铣猩。下一章會介紹另一個對象創(chuàng)建模式揖铜,它并不使用copy方法創(chuàng)建同一類型的對象,而是使用一個決定生成何種對象的方法达皿。
第4章 ?工 ? 廠 ?方 ?法
工廠方法也稱為虛構(gòu)造器蛮位。它適用于這種情況:一個類無法預期需要生成哪個類的對象较沪,想讓其子類來指定所生成的對象。
工廠方法模式:定義創(chuàng)建對象的接口失仁,讓子類決定實例化哪一個類尸曼。工廠方法使得一個類的實例化延遲到其子類。
何時使用工廠方法:
- 編譯時無法準確預期要創(chuàng)建的對象的類萄焦;
- 類想讓其子類決定在運行時創(chuàng)建什么控轿;
- ?類有若干輔助類為其子類,而你想將返回哪個子類這一信息局部化拂封。
使用這一模式的最低限度是茬射,工廠方法能給予類在變更返回哪一種對象這一點上更多的靈活性。使用這一架構(gòu)的一個常見例子是Cocoa Touch框架中的NSNumber.盡管可以使用常見的alloc init兩步法創(chuàng)建NSNumber實例冒签,但這沒什么用在抛,除非使用預先定義的類工廠方法來創(chuàng)建有意義的實例。工廠方法模式對框架設(shè)計者特別有用萧恕。
為何這是創(chuàng)建對象的安全方法
與直接創(chuàng)建新的具體對象相比刚梭,使用工廠方法創(chuàng)建對象可算作一種最佳做法。工廠方法模式讓客戶程序可以要求有工廠方法創(chuàng)建的對象擁有一組共同的行為票唆。所以往類層次結(jié)構(gòu)中引入新的具體產(chǎn)品并不需要修改客戶端代碼朴读,因為返回的任何具體對象的接口都跟客戶端一直在用的從前的接口相同。
在Cocoa Touch框架中應用工廠方法
就NSNumber而言走趋,沒有可在別處生成的其他“數(shù)字生成器”衅金,而是在類級別打包提供了方法以達到類似的效果。它們稱作類工廠法簿煌。
總結(jié)氮唯,工廠方法是面向?qū)ο筌浖O(shè)計中應用非常普遍的設(shè)計模式。工廠方法從代碼中消除了對應用程序特有類的耦合姨伟。代碼只需要處理prodect抽象接口您觉。所以同一代碼得以復用,在應用程序中與用戶定義的任何ConcreteProcuct類一起工作授滓。我們使用工廠方法模式協(xié)助實現(xiàn)了TouchPainter應用程序琳水,使其支持多種CanvasView以供用用戶選擇。
在下一章般堆,將接觸到工廠方法模式密切相關(guān)另一種對象創(chuàng)建模式在孝。
第5章 ?抽 ?象 ?工 ?廠
抽象工廠: 提供一個創(chuàng)建一系列相關(guān)或相互依賴對象的接口,而無需指定它們具體的類淮摔。
兩個工廠模式的對比
抽象工廠: 通過對象組合創(chuàng)建抽象產(chǎn)品私沮;創(chuàng)建多系列產(chǎn)品;必須修改父類的接口才能支持新的產(chǎn)品和橙。
工廠方法:通過類繼承創(chuàng)建抽象產(chǎn)品仔燕;創(chuàng)建一種產(chǎn)品造垛; 子類化創(chuàng)建者并重載工廠方法以創(chuàng)建新產(chǎn)品。
把抽象工廠應用到TouchPainter應用程序
軟件設(shè)計的黃金法則:變動需要抽象
當現(xiàn)有的抽象工廠需要支持新產(chǎn)品時晰搀,需要向父類添加相應的新工廠方法五辽。
在Cocoa Touch 框架中使用抽象工廠
抽象工廠模式常見于Cocoa Touch框架。有很多基礎(chǔ)類采用了這一模式外恕。特別常見的一個就是天天在用的NSNumber杆逗。
總結(jié):抽象工廠模式是一種極為常見的設(shè)計模式。它是最基本的鳞疲,因為它可以涉及許多類型的對象創(chuàng)建罪郊。一系列相關(guān)類的好的模式,應該作為一種抽象尚洽,不為客戶端所見悔橄。抽象工廠可以順暢地提供這種抽象,而不暴露創(chuàng)建過程中任何不必要的細節(jié)或所創(chuàng)建對象的確切類型腺毫。下一章要討論創(chuàng)建抽象對象的另一種方法——生成器模式
第6章 ? ? 生 ?成 ?器
如果能夠把構(gòu)建過程分解為客戶-指導者-生成器(client-director-builder)的關(guān)系癣疟,那么過程將更容易管理與復用。針對此類關(guān)系的設(shè)計模式稱為生成器拴曲。
builder是一個抽象接口争舞,聲明了一個builderPart方法凛忿,該builder方法由ConcreteBuilder實現(xiàn)澈灼,以構(gòu)造實際產(chǎn)品Product。ConcreteBuilder有個getResult方法店溢,向客戶端返回構(gòu)造完畢的Product. ? ?Director定義了一個construct方法叁熔,命令builder的實例去buildPart。 ?Director和Builder形成一種聚合關(guān)系床牧。這意味著builder是一個組成部分荣回,與Director結(jié)合,以使整個模式運轉(zhuǎn)戈咳,但同時心软,Director并不負責Builder的生存期。
生成器模式:將一個復雜對象的構(gòu)建與它的表現(xiàn)分離著蛙,使得同樣的構(gòu)建過程可以創(chuàng)建不同的表現(xiàn)删铃。
何時使用生成器模式
- 需要創(chuàng)建涉及各種部件的復雜對象入问。創(chuàng)建對象的算法應該獨立于部件的裝配方式排拷。常見例子是構(gòu)建組合對象。
- 構(gòu)建過程需要以不同的方式構(gòu)建對象会放。
生成器與抽象工廠的對比
兩者大不相同顷蟆,一方面生成器關(guān)注的是分步創(chuàng)建復雜對象诫隅,很多時候同一類型的對象可以以不同的方式創(chuàng)建腐魂。另一方面,抽象工廠的重點在于創(chuàng)建簡單或復雜產(chǎn)品的套件逐纬。生成器在多步創(chuàng)建過程的最后一步返回產(chǎn)品蛔屹,而抽象工廠則立即返回產(chǎn)品。
兩者的區(qū)別主要是:
生成器: 構(gòu)建復雜對象风题;以多個步驟構(gòu)建對象判导;以多種方式構(gòu)建對象;在構(gòu)建過程的最后一步返回產(chǎn)品沛硅;專注一個特定產(chǎn)品眼刃。
抽象工廠:構(gòu)建簡單或復雜對象;以單一步驟構(gòu)建對象摇肌;以單一方式構(gòu)建對象擂红;立刻返回產(chǎn)品;強調(diào)一套產(chǎn)品围小。
總結(jié): 生成器模式能幫助構(gòu)建涉及部件與表現(xiàn)的各種組合的對象昵骤。沒有這一模式,知道構(gòu)建對象所需細節(jié)的Director可能最終會變成一個龐大的神類肯适。
下一章將討論一種只生成并返回類的單一實例的模式变秦。
第7章 ? ? ? ?單 ? ?例
這一模式的意圖是使得類的一個對象成為系統(tǒng)中的唯一實例。要實現(xiàn)這一點框舔,可以從客戶端對其進行實例化開始蹦玫。
單例模式:保證一個類僅有一個實例,并提供一個訪問它的全局訪問點刘绣。
何時使用單例模式
- 類只能有一個實例樱溉,而且必須從一個為人熟知的訪問點對其進行訪問,比如工廠方法纬凤;
- 這個唯一的實例只能通過子類化進行擴展福贞,而且擴展的對象不會破壞客戶端代碼。
單例模式提供了一個為人熟知的訪問點停士,供客戶類為共享資源生成唯一實例挖帘,并通過它對共享資源進行訪問。雖然靜態(tài)的全局對象引用或類方法也可以提供全局訪問點恋技,但是全局對象無法防止類被實例化一次以上拇舀,而且類方法也缺少消除耦合的靈活性。
單例類提供創(chuàng)建與訪問類的唯一對象的訪問點猖任,并保證它唯一你稚、一致而且為人熟知。這一模式提供了靈活性,使其任何子類可以重載實例方法并且完全控制自身的對象創(chuàng)建刁赖,而不必修改客戶端的代碼搁痛。更好的是,父類中的實例實現(xiàn)可以處理動態(tài)對象創(chuàng)建宇弛。類的實際類型可以在運行時決定鸡典,以保證創(chuàng)建正確的對象。
在OC中實現(xiàn)單例模式
要把一個單例類設(shè)計得恰當枪芒,有些事情必須要考慮清楚彻况。需要問的第一個問題是,如何保證類只能創(chuàng)建一個實例舅踪。
如果需要實現(xiàn)單例模式的“嚴格”版本纽甘,要想在實際中使用,需要面對以下兩個主要的障礙抽碌。
- 發(fā)起調(diào)用的對象(calling ?object)不能以其他分配方式實例化單例對象悍赢。否則,就有可能創(chuàng)建單例類的多個實例货徙。
?- 對單例對象實例化的限制應該與引用計數(shù)內(nèi)存模型共存左权。
線程安全
如果單例對象由多個線程訪問,那么使它線程安全(thread-safe)至關(guān)重要痴颊。要讓它線程安全赏迟,需要在sharedSingleton_靜態(tài)實例的nil檢查周圍加入一些@synchronized()程序塊或者NSLock實例。如果有其他屬性需要保護蠢棱,也可以把它們聲明為atomic型锌杀。