iOS 原型模式

原型模式是非常簡單的一種設(shè)計(jì)模式, 在多數(shù)情況下可被理解為一種深復(fù)制的行為。在Objective-C中使用原型模式, 首先要遵循NSCoping協(xié)議(OC中一些內(nèi)置類遵循該協(xié)議, 例如NSArray, NSMutableArray等)。剛才我們提到了深復(fù)制, 一圖以蔽之:

Two kinds of Copy

深復(fù)制就是開辟新內(nèi)存實(shí)現(xiàn)真正的內(nèi)存復(fù)制, 淺復(fù)制, 只復(fù)制指針, 堆內(nèi)存不變. 在我們設(shè)計(jì)系統(tǒng)時(shí), 有時(shí)一些對象需要根據(jù)用戶操作完成拷貝備份等操作, 這時(shí)候, 如果再去按照原來的方法初始化一遍對象就會帶來一些不便和問題:

  1. 該對象的某些屬性是在用戶操作過程中產(chǎn)生的, 不能夠僅憑一個(gè)initXXX方法賦值;
  2. 常規(guī)賦值太過麻煩, 而且破壞封裝.

這時(shí)候原型模式的優(yōu)勢便體現(xiàn)出來了??偨Y(jié)下原型模式的使用情況:

  1. 需要?jiǎng)?chuàng)建的對象應(yīng)獨(dú)立于其類型與創(chuàng)建方式。也就是說我們想要的對象并不能夠直接通過初始化函數(shù)來創(chuàng)建出來,其創(chuàng)建過程不具有普遍性且復(fù)雜。
  2. 要實(shí)例化類是在運(yùn)行時(shí)決定的。在編寫代碼的時(shí)候并不知道哪種對象會被創(chuàng)建出來,其內(nèi)部的結(jié)構(gòu)如何復(fù)雜(例如:復(fù)雜程度取決于用戶的操作)。
  3. 不想要與產(chǎn)品層次相對應(yīng)的工廠層次。不通過工廠方法或者抽象工廠來控制產(chǎn)品的創(chuàng)建過程,想要直接復(fù)制對象
  4. 不同類的實(shí)例間的差異僅是狀態(tài)的若干組合。因此復(fù)制相應(yīng)數(shù)量的原型比手工實(shí)例化更加方便。
  5. 類不容易創(chuàng)建,比如每個(gè)組件可把其他組件作為子節(jié)點(diǎn)的組合對象。復(fù)制已有的組合對象并對副本進(jìn)行修改會更加容易。如果內(nèi)部結(jié)構(gòu)復(fù)雜,不容易重現(xiàn)。

常見的使用場景 : 結(jié)構(gòu)復(fù)雜的類型, 例如《編程之道》中提及的Mark類型; 或者是相似類, 結(jié)構(gòu)一致, 但是屬性不同.

Demo

首先創(chuàng)建一個(gè)Player類, 擁有2個(gè)屬性highestLevel和currentLevel, 同時(shí)提供2個(gè)public方法修改這2個(gè)屬性. 代碼如下:

@interface Player : NSObject <NSCopying>
/**
 *  update player's current level during game
 *
 *  @param level
 */
- (void)updateCurrentLevel:(NSInteger)level;


/**
 *  update player's highest level during game
 *
 *  @param level
 */
- (void)updateHighestLevel:(NSInteger)level;

@end

最為關(guān)鍵的是Player需要實(shí)現(xiàn)NSCopying協(xié)議:

#pragma mark - Override
- (instancetype)copyWithZone:(NSZone *)zone
{
    Player *copyPlayer = [[[self class] allocWithZone:zone] init];
    copyPlayer.highestLevel = self.highestLevel;
    copyPlayer.currentLevel = self.currentLevel;

    return copyPlayer;
}

這里大家看到NSZone類型, 這是個(gè)什么類型呢? 其實(shí)它是一個(gè)結(jié)構(gòu)體, 是為了防止內(nèi)存碎片化而引入的一個(gè)結(jié)構(gòu). NSZone會根據(jù)你想要開辟的內(nèi)存大小來分配內(nèi)存, 提高內(nèi)存管理. 然而官方的Programming with ARC Release Note也指出, 目前的runtime系統(tǒng)忽略了區(qū)域的概念,因?yàn)楸旧淼膬?nèi)存管理已經(jīng)非常有效率,使用Zone反而會降低內(nèi)存使用,訪問效率, 增加源代碼復(fù)雜度等.所以一般不使用NSZone, 而在這個(gè)例子中, 雖說使用了allocWithZone的方法, 但是我們進(jìn)去看源代碼則會發(fā)現(xiàn): Apple其實(shí)還是用一般的初始化方法代替了原來的Zone開辟:

#pragma mark - Override
- (instancetype)copyWithZone:(NSZone *)zone
+ (instancetype)allocWithZone:(struct _NSZone *)zone OBJC_SWIFT_UNAVAILABLE("use object         
  initializers instead"); 

原型設(shè)計(jì)模式基本就是這些, 當(dāng)然我們的Player類可以變成一個(gè)接口, 讓子類去實(shí)現(xiàn), 更好的體現(xiàn)面向接口編程.

結(jié)果

2015-09-18 21:30:32.072 DP_Prototype[1173:280693] <Player: 0x14d513f60>
2015-09-18 21:30:32.073 DP_Prototype[1173:280693] <Player: 0x14d5337e0>

在其他文件調(diào)用copy方法, 即可看到系統(tǒng)為我們新開辟的一塊內(nèi)存, 引用計(jì)數(shù)為1.

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • 原型模式copy()、NSCopying協(xié)議數(shù)組、字典、集合中的元素也要可以復(fù)制,即實(shí)現(xiàn)NSCopy協(xié)議,否則崩潰...
    印林泉閱讀 456評論 0 1
  • *面試心聲:其實(shí)這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個(gè)offer,總結(jié)起來就是把...
    Dove_iOS閱讀 27,610評論 30 472
  • 1大同小異的工作周報(bào) Sunny軟件公司一直使用自行開發(fā)的一套OA (Office Automatic,辦公自動化...
    justCode_閱讀 1,240評論 0 3
  • 1 場景問題# 1.1 訂單處理系統(tǒng)## 考慮這樣一個(gè)實(shí)際應(yīng)用:訂單處理系統(tǒng)。 現(xiàn)在有一個(gè)訂單處理的系統(tǒng),里面有個(gè)...
    七寸知架構(gòu)閱讀 4,660評論 3 63
  • 設(shè)計(jì)模式匯總 一、基礎(chǔ)知識 1. 設(shè)計(jì)模式概述 定義:設(shè)計(jì)模式(Design Pattern)是一套被反復(fù)使用、多...
    MinoyJet閱讀 4,091評論 1 15

友情鏈接更多精彩內(nèi)容