iOS架構補完計劃--設計模式

目錄
- 官方用到的幾種設計模式
- 代理模式(Proxy)
- 觀察者模式(Observer)
- 單例模式(Singleton)
- 工廠模式(Factory)
- 策略模式(Strategy)
- 裝飾模式(Decorator)
- 介面卡模式(Adapter)
- MVC及一些衍生設計模式
官方用到的幾種設計模式
官方的用法總是我們很關心、也是值得學習的
代理模式(Proxy Pattern)
當一個類的某些功能需要由別的類來實現、但是又不確定具體會是哪個類實現。
有兩個主體:委託者( 方法呼叫者
)、代理者( 方法實現者
)。
Cocoa下的應用:
UITableView、UIAlertView、NSURLSession等等
觀察者模式(Observer)
主要負責物件間的通訊。
觀察者註冊自己感興趣的事件、被觀察者不需要知道觀察者的存在。
-
通知
Cocoa下的應用:
鍵盤升降( UIKeyboardWillShowNotification
、 UIKeyboardWillHideNotification
)、前後臺切換( name:UIApplicationDidEnterBackgroundNotification
、 UIApplicationDidBecomeActiveNotification
)等等
-
KVO
具體應用:下載進度條、表單填寫狀態的更新。
不過實際上cocoa並沒有給我們暴露直接使用KVO的例子。
單例模式(Singleton)
主要用於共享資源、並且確保該例項只被初始化一次。
Cocoa下的應用:
[NSUserDefaults standardUserDefaults]
、 [UIApplication sharedApplication]
、 [UIScreen mainScreen]
、 [NSFileManager defaultManager]
等等。
工廠模式
專門定義一個類來負責建立其他類的例項、被建立的例項常常具有共同的父類(基於多型)。
工廠模式分為三種:簡單工廠模式、工廠模式、抽象工廠模式。
-
簡單工廠模式
由一個工廠類、根據傳入的引數( 通常是列舉
)、動態的決定創建出哪一個產品類的例項。
適用於負責建立的物件比較少的情況下使用、簡單工廠的穩定性和可擴充套件性會隨著數量的增加而下降。
需要以下三個元素:
1. 工廠(Factory)
角色接受客戶端的請求、通過請求負責建立相應的產品物件。
2. 抽象產品(Abstract Product)
工廠模式所建立物件的父類或是共同擁有的介面、可是抽象類或介面< 也就是協議
>。
3. 具體產品(ConcreteProduct)
工廠模式所建立的物件都是這個產品例項。
工廠實現:
//AnimalHouse + (Animal *)animalWithType:(AnimalType)type { Animal *animal = nil; if (type == AnimalTypeDog) {//狗 animal = [[Dog alloc] init]; } else if (type == AnimalTypeCat) { animal = [[Cat alloc] init]; } else if (type == AnimalTypeSheep) { animal = [[Sheep alloc] init]; } return animal; }
使用起來:
Animal *dog = [AnimalHouse animalWithType:AnimalTypeDog]; [dog shout]; Animal *cat = [AnimalHouse animalWithType:AnimalTypeCat]; [cat shout]; Animal *sheep = [AnimalHouse animalWithType:AnimalTypeSheep]; [sheep shout];
需要注意的是、如果只是將引數賦值給產品( 比如顏色等等
)、是並不能算作簡單工廠模式的。
-
工廠模式(Factory)
相比簡單工廠、將《工廠》也進行抽象處理。
解決了簡單工廠模式下、臃腫的工廠導致增加產品時不宜擴充套件的弊端。
需要以下四個角色:
1. 抽象工廠
與業務方無關、任何在模式中建立物件的工廠必須實現這個介面。
2. 具體工廠
實現了抽象工廠介面的具體類、含有與引用密切相關的邏輯、並且受到業務方的呼叫以建立產品物件。
3. 抽象產品
工廠方法所建立產品物件的超型別,也就是產品物件的共同父類或共同擁有的介面。
4.具體產品
這個角色實現了抽象產品角色所聲名的介面。工廠方法所建立的每個具體產品物件都是某個具體產品角色的例項。
以其中一個工廠為例:
與抽象工廠 AnimalHouse
(動物之家)相比、具體工廠 DogHouse
(狗窩)隸屬於動物園。狗窩裡自然全是狗~
//DogHouse + (Animal *)animal { Animal *animal = [[Dog alloc] init]; return animal; }
使用起來:
Animal *dog = [DogHouse animal]; [dog shout]; Animal *cat = [CatHouse animal]; [cat shout]; Animal *sheep = [SheepHouse animal]; [sheep shout];
雖然解決了擴充套件性。但依舊有個問題、就是當工廠太多、業務需要使用的工廠型別也太多了~
-
抽象工廠模式
與工廠模式的基本模式相同。最大的區別就是工廠例項不在只生產一種產品、而是生產一個產品族。
抽象工廠實現:
//AnimalHouse + (AnimalHouse *)houseWithType:(AnimalType)type { AnimalHouse *house = nil; if (type == AnimalTypeDog) {//狗 house = [[DogHouse alloc] init]; } else if (type == AnimalTypeCat) { house = [[CatHouse alloc] init]; } else if (type == AnimalTypeSheep) { house = [[SheepHouse alloc] init]; } return house; }
具體使用:
//內部生成具體工廠`DogHouse ` // AnimalHouse *animalHouse = [AnimalHouse houseWithType:AnimalTypeDog]; //或者也可以直接使用具體工廠 AnimalHouse *animalHouse = [[DogHouse alloc] init]; //內部生成具體產品`MaleDog` MaleAnimal* maleAnimal = [animalHouse maleAnimal]; //內部生成具體產品`femaleDog` FemaleAnimal* femaleAnimal = [animalHouse femaleAnimal]; //使用該產品 [maleAnimal shout]; [femaleAnimal shout];
Cocoa下的應用:
Cocoa框架下使用的為抽象工廠模式、具體使用的物件為 NSString
、 NSArray
、 NSDictionary
(包括可變物件)以及 NSNumber
。
以陣列為例:
id obj1 = [NSArray alloc]; id obj2 = [NSMutableArray alloc]; id obj3 = [obj1 init]; id obj4 = [obj2 init]; id obj5 = [UIView alloc]; id obj6 = [obj5 init]; NSLog(@"%@",NSStringFromClass([obj1 class])); NSLog(@"%@",NSStringFromClass([obj2 class])); NSLog(@"%@",NSStringFromClass([obj3 class])); NSLog(@"%@",NSStringFromClass([obj4 class])); NSLog(@"%@",NSStringFromClass([obj5 class])); NSLog(@"%@",NSStringFromClass([obj6 class]));
列印結果:
__NSPlaceholderArray __NSPlaceholderArray __NSArray0 __NSArrayM UIView UIView
可見陣列與View不同。alloc生成的物件並不是最終的 《產品》 、而是一個 《工廠》 。
而且是一個單例工廠:
NSArray * obj1 = [NSArray alloc]; NSArray * obj2 = [NSArray alloc]; NSMutableArray * obj3 = [NSMutableArray alloc]; NSMutableArray *obj4 = [NSMutableArray alloc]; NSLog(@"%p",obj1); NSLog(@"%p",obj2); NSLog(@"%p",obj3); NSLog(@"%p",obj4);
輸出:
0x604000010360 0x604000010360 0x604000010350 0x604000010350
策略模式(Strategy)
策略模式其實和工廠模式類似、都是利用繼承(或者協議)的方式實現。
只是 《工廠模式更像是對物件的管理》 、而 《策略模式是對行為的管理》 。
舉個最常見的例子:AFNetworking下的 AFHTTPRequestSerializer
與 AFJSONResponseSerializer
、二者分別負責編碼與解碼的策略。
以解碼為例、你可以使用不同的策略:
AFJSONResponseSerializer
、 AFXMLParserResponseSerializer
、 AFXMLDocumentResponseSerializer
等等。將伺服器返回的資料解析成不同的結果。
在Cocoa下的應用:
陣列排序的: sortedArrayUsingSelector
方法。
他會依居陣列內部不同元素、採用不用元素的排序策略。
裝飾模式(Decorator)
是在不改變原封裝的前提下,為物件動態新增新功能的模式
主要通過 Extension
和 Category
來實現
在Cocoa下的應用:
最常用的例子就是 NSObject
的 performSelector
方法集
NSObject (NSThreadPerformAdditions):
- (void)performSelectorInBackground:(SEL)aSelector withObject:(nullable id)arg; - (void)performSelectorOnMainThread:(SEL)aSelector withObject:(nullable id)arg waitUntilDone:(BOOL)wait;
@interface NSObject (NSDelayedPerforming):
- (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay inModes:(NSArray<NSRunLoopMode> *)modes; - (void)performSelector:(SEL)aSelector withObject:(nullable id)anArgument afterDelay:(NSTimeInterval)delay;
介面卡模式(Adapter)
將一個類的介面轉化為另一個類的介面、使得原本互不相容的類可以通過介面一起工作
從某些意義上來講、某些情況下的代理模式也算介面卡模式。
委託者
通過 代理(介面卡)
要求 代理者
提供合適的資源。
介面卡分為:
- 類介面卡
以(多)繼承的方式實現、被適配類的子類通過多繼承的方式進行格式化輸出。 - 物件介面卡
存在一個介面卡物件、用來將被適配物件進行格式化輸出。
實現一個介面卡、我們至少需要以下三個物件:
1. 被適配者(Adoptee)
通常為舊模組
2. 適配目標(Target)
通常為協議介面
3. 介面卡(Adopter)
類介面卡為Adoptee的子類、物件介面卡為持有Adoptee的第三者。
4. 使用者(Client)
最終資訊的接受者

在Cocoa下的應用:
UITableView(Client)
作為向 UIViewController
( Adopter
)尋求格式為 UITableViewDataSource(Target)
的資源。
而 UIViewController
( Adopter
)、則通過對自身持有的資料來源 NSArray(Adoptee)
進行格式化處理後、交付給 UITableViewDataSource(Target)
。
Demo的話可以看看 ofollow,noindex">《介面卡模式的解析-iOS》 或者 《IOS設計模式淺析之介面卡模式(Adapter)》
MVC及一些衍生設計模式
iOS架構補完計劃--淺談MVC及其衍生架構模式(附簡易圖解)
最後
本文主要是自己的學習與總結。如果文記憶體在紕漏、萬望留言斧正。如果不吝賜教小弟更加感謝。