Objective-C之原型模式

原型模式

原型模式是非常簡單的一種模式,在我們的實際開發中經常用到這種模式,例如你創建的可變字典、可變字符串調用copy來生成新的對象,那么你在這個過程中已經使用了原型模式。還有比如你在寫論文的時候,給老師交的初稿,退回來之后再修改你肯定不是在初稿上修改的,也不是再從新敲一遍,而是復制一份初稿再修改,這個拷貝初稿生成終稿的過程就叫原型模式。

舉個例子:你創建了一個Student類,屬性有性別sex、名字name、年級className、班主任teacher、年齡years。然后開始創建學生對象:小江、小帥、小虎等多個對象,在創建的過程中發現這些人是同班學生、除了性別和名字有差別之外其他的信息基本一樣,如果初始化這些學生對象然后給每個屬性賦值,顯然這些代碼都是重復性的代碼。so通過讓Student類遵守NSCopying的協議,就能通過copy快速的初始化對象,然后根據差異簡單的改變sex和那么即可。(ps:例子只是為了說明這種模式,相信大家還有很多更好的辦法,我現在在學習GoF的《Objective-C的編程之道,iOS設計模式解析》所以現在以簡書的形式來做個筆記供大家相互學習和指正,之后會不斷的將在這本書理解到的東西轉到簡書上)

原型模式的定義:使用原型實例指定創建對象的種類,并通過復制這個原型創建新的對象。《設計模式》(Addison-Weslet,1994)


?何時使用原型模式:

? ? ? ? 1、需要創建的對象應獨立于其類型與創建方式。

? ? ? ? 2、要實例化的類是在運行時決定的。

? ? ? ? 3、不想要與產品層次相對應的工廠層次。

? ? ? ? 4、不同類的實例間的差異僅是狀態的若干組合。因此復制相應數量的原型比手工實例化更加方便。

? ? ? ? 5、類不容易創建,比如每個組件可把其他組件作為子節點的組合對象。復制已有的組合對象并對副本進行修改會更加容易。

在GoF的書中有句話很好:從功能的角度來看,不管什么對象,只要復制本身比手工實例化要好,那么都可以是原型對象。使用設計模式更像藝術行為而非科學行為。


深拷貝&淺拷貝

淺拷貝:只是復制指針,且復制的指針的指向還是原來的內存資源,并沒有在內存中開辟新的資源,和原來的指針指向一塊內存資源。

深拷貝:不但拷貝了指針,而且也將原指針指向的資源進行了拷貝,相當于開辟了新的內存,把原來的資源也拷貝了一份并且各自的指針指向各自的資源。

Coco Touch 框架中根類(NSOblect)的衍生類提供了實現深復制的協議(NSCopying)。NSObject有一個實例方法(id)copy,這個方法默認調用了[self copyWithZone:nil],對于引用了NSCopying協議的子類,必須實現(id)copyWithZone:(NSZone *)zone方法,否則將引發異常。(輸出如下)


assign&copy&retain

直接看例子

@interface IDStudent : NSObject

@property (assign, nonatomic, getter=isMale)BOOL male;

@property (copy, nonatomic)NSString *name;

@property (copy, nonatomic)NSString *className;

@property (copy, nonatomic)NSString *teacher;

@property (assign, nonatomic)NSUInteger years;

@property (assign, nonatomic)NSMutableString *name1;

@property (retain, nonatomic)NSMutableString *name2;

@property (copy, nonatomic)NSMutableString *name3;

+ (instancetype)studentWithName:(NSString *)name male:(BOOL)male className:(NSString *)className teacher:(NSString *)teacher yeas:(NSUInteger)years;

@end

?NSMutableString *str =[NSMutableString stringWithFormat:@"小帥"];? ?

IDStudent *student =[IDStudent new]; ? ?

student.name1 =str; ? ?

student.name2 =str; ? ?

student.name3 =str; ?? ? ? ?

NSLog(@"\n str的地址:%p\n name1的地址:%p(assign) \n name2的地址:%p(retain)\n name3的地址:%p(copy)\n",str,student.name1,student.name2,student.name3);


輸出結果

str的地址:0x60c000240e10

name1的地址:0x60c000240e10(assign)

name2的地址:0x60c000240e10(retain)

name3的地址:0x60c000036760(copy)

結論:

解析一下代碼:NSMutableString *str =[NSMutableString stringWithFormat:@"小帥"];

1、在棧區開辟內存來存str,比如地址為:0xFFFF,內容為0x60c000240e10

2、在堆區開辟內存來存str的內容@"小帥",地址為0x60c000240e10,內容為@"小帥"

assing:如果在MRC的情況下打印retainCount,它的值不會加1,(自己可以試試),且在堆區的地址還是和str的地址一樣,說明assign只是一個str的影子

retain:這個接觸到MRC的情況下,它的值會加1,雖然它的地址還是和str的一樣,但是它會在棧區開辟新的空間比如0xWWWW,但是內容還是0x60c000240e10相當于經過retain的name2在棧區開辟了新的空間,都是強指向在堆區地址為0x60c000240e10的內容,共同管理。

copy:使用copy后堆區的地址改變,說明這個過程在棧區開辟了新的空間地址為0xBBBB,儲存的內容為0x60c000036760同樣也在堆區開辟了新的空間,地址為:0x60c000036760內容為@“小帥”。跟原來的str沒有了關系,說明進行了深拷貝。


下邊對NSString在進行一下實驗,看是否和NSMutableString一樣的儲存方式

NSString *name =[NSString stringWithFormat:@"name"]; ? ?

NSString *nameCopy =[name copy]; ? ?

NSMutableString *mName =[name mutableCopy]; ? ?

NSLog(@"\nname:%p\nnameCopy:%p\nmName:%p\n",name,nameCopy,mName); ?? ? ? ?

NSMutableString *str =[[NSMutableString alloc]initWithString:@"test"]; ? ?

NSMutableString *copyStr =[str copy]; ? ?

NSLog(@"\n------------------------------------\nstr:%p\ncopyStr:%p",str,copyStr);

輸出結果:

2017-12-22 16:34:02.566672+0800 desgin_原型模式[25958:11425087]

name:0xa000000656d616e4

nameCopy:0xa000000656d616e4

mName:0x60c00024c360

2017-12-22 16:34:02.566808+0800 desgin_原型模式[25958:11425087]

------------------------------------------------------------------------

str:0x60c00024ca50

copyStr:0xa000000747365744

結論:根據輸出結果NSString的不可變字符串在copy的情況地址一致,由于copy返回的是不可變副本,系統只生成一份內存資源,此時的copy只是淺拷貝,和retain作用一樣。

通過mutableCopy地址不一致,生成的是可變副本,開辟了新的內存空間,是深拷貝。而NSMutableString的copy會開辟新的空間。

本文代碼

ps:第一次寫文章,想要改變一下自己,之前習慣做筆記,現在也要分享各位同學,這篇文章參考了好多的這位哥們的這篇博客,我寫的有什么不對的地方希望大家多多指正!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,835評論 6 534
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,676評論 3 419
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,730評論 0 380
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,118評論 1 314
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,873評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,266評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,330評論 3 443
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,482評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,036評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,846評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,025評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,575評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,279評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,684評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,953評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,751評論 3 394
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,016評論 2 375

推薦閱讀更多精彩內容