iOS開發那些事-iOS常用設計模式–委托模式
對於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方法。
最後更新:2017-04-04 07:03:49