對於iOS開發,舉例Cocoa架構下的幾個設計模式為大家分析。當然,Cocoa架構下關於設計模式的內容遠遠不止這些,我們選擇了常用的幾種:單例模式、委託模式、觀察者模式、MVC模式。
委託模式
委託模式從GoF 設計裝飾(Decorator)、適配器(Adapter)和模板方法(Template Method)等模式演變而來。幾乎每一個應用都會或多或少地使用到委託模式。不只是CocoaTouch架構,在Cocoa架構中委託模式也得到了廣泛的應用。
問題提出
對於應用生命週期的非運行狀態——應用啟動情境,我們把從點擊表徵圖到第一個畫面啟動的過程細化了一下
假設這一系列的處理,都是在一個上帝類UIApplication完成的。之所以叫“上帝類(God Class)”,是因為它“無所不能”、“包含所有”。 在物件導向的軟體設計中“上帝類”不是很友好, 需要重構。在編程過程中要盡量避免上帝類的使用,因為上帝類是高耦合的,職責不清,所以難以維護。我們需要“去除上帝類”,把看似功能很強且很難維護的 類,按照職責把自己的屬性或方法指派到各自的類中或分解成功能明確的類,從而去掉“上帝類”。
幸運的是蘋果沒有把UIApplication類設計成“上帝類”,蘋果處理分割到兩個不同的角色類中,其中一個扮演架構類角色,架構類具有通用、 可重複使用、與具體應用無關等特點。另一個扮演應用相關類的角色,應用相關類與具體應用有關,由於要受到架構類的控制,常常被設計成為“協議”,在 Java中稱之為“介面”。開發人員需要在具體的應用中實現這個“協議”。
將application:didFinishLaunchingWithOptions:和 applicationDidBecomeActive:完成功能提取出來,定義在UIApplicationDelegate協議中,這樣 UIApplication類就變成了架構類。
在具體使用時候需要實現UIApplicationDelegate協議,HelloWorld應用的類圖。UIApplication不直接依賴 於AppDelegate類,而是依賴於UIApplicationDelegate協議,這在物件導向軟體設計原則中叫做“面向介面的編程”。 AppDelegate類實現協議UIApplicationDelegate,它是委託類。
我們給出委託的定義,委託是為了降低一個對象的複雜度和耦合度,使其能夠更具通用性將其中一些處理置於委派物件中的編碼方式。通用類因為通用性即與 具體應用的無關性而變為架構類,架構類保持委派物件的引用,並在特定時刻向委派物件發送訊息。訊息可能只是通知委派物件做一些事情,也可能是對委派物件進 行控制。
實現原理
我們通過一個案例介紹委託設計模式實現原理和應用情境,重新繪製委託設計模式類圖。
在古希臘有一個哲學家,他畢生只做三件事情:“睡覺”、“吃飯”和“工作”。為更好的生活,工作效率更高,他會找一個徒弟,把這些事情委託給徒弟做。然而要成為他的徒弟,需要實現一個協議,協議要求能夠處理“睡覺”、“吃飯”和“工作”問題。 三者之間的關係。
哲學家類圖中, 通用類(Philosopher)保持指向委派物件(ViewController)的“弱引用” (id<PhilosopherDelegate> delegate),委派物件(ViewController)就是哲學家的“徒弟”,他實現了協議 PhilosopherDelegate,PhilosopherDelegate規定了3個方法:-(void) sleep、-(void) eat和-(void) work方法。
下面我們看看實現代碼,委託協議PhilosopherDelegate.h代碼如下:
@protocol PhilosopherDelegate@required-(void) sleep;-(void) eat;-(void) work;@end
委託協議PhilosopherDelegate定義了3個方法,協議沒有m檔案,它的定義可以放在別的h檔案中。它的實作類別就是委託類ViewController的代碼如下:
//// ViewController.h//@interface ViewController : UIViewController<PhilosopherDelegate>@end//// ViewController.m//@implementation ViewController- (void)viewDidLoad{ [super viewDidLoad]; Philosopher *obj = [[Philosopher alloc ] init]; obj.delegate = self; [obj start];}#pragma — PhilosopherDelegate 方法實現-(void) sleep{ NSLog(@”sleep…”);}-(void) eat{ NSLog(@”eat…”);}-(void) work{ NSLog(@”work…”);}@end
委派物件如何與通用類建立參考關聯性呢?我們通過viewDidLoad方法中的obj.delegate = self語句來指定委派物件和通用類間的參考關聯性。 一般情況下通用類由架構直接提供,在這個例子中我們根據需要自己實現了通用類Philosopher,Philosopher.h的代碼:
//// Philosopher.h// DelegatePattern//#import “PhilosopherDelegate.h”@interface Philosopher : NSObject{ NSTimer *timer; int count;}@property (nonatomic, weak) id<PhilosopherDelegate> delegate;-(void) start;-(void) handle;@end
Philosopher.h中定義delegate屬性,它的類型是id<PhilosopherDelegate>,它可以儲存委派物件的引用,屬性weak說明是“弱引用”。Philosopher.m檔案代碼如下:
//// Philosopher.m// DelegatePattern#import “Philosopher.h”@implementation Philosopher@synthesize delegate;-(void) start{ count= 0; timer = [NSTimer scheduledTimerWithTimeInterval:3.0 target:self selector:@selector(handle)userInfo:nil repeats:YES];}-(void)handle{ switch (count) { case 0: [self.delegate sleep]; count++; break; case 1: [self.delegate eat]; count++; break; case 2: [self.delegate work]; [timer invalidate]; break; }}@end
在本例中Philosopher類比一些通用類發出調用,這個調用的發出是通過NSTimer每3秒發出一個,依次向委派物件發出訊息sleep、 eat和work。代碼中self.delegate是指向委派物件ViewController的引用,[self.delegate sleep]是調用ViewController中的sleep方法。