2012-11-02 93 views
35

雖然最近使用Objective-C和其中編寫的各種庫,但我注意到了兩種非常流行的單例模式。一個版本獲取單例實例並調用它的實例方法,而其他版本只暴露類方法,並且從不給你一個實例來處理。所有的目的都是抽象化訪問單個資源(StoreKit,CoreData,Parse API等)。例如,這裏是在MKStoreKit採用前一種方法:單例實例vs類方法

// initialize singleton during app boot 
[MKStoreManager sharedManager] 

// sometime later in the app 
[[MKStoreManager sharedManager] buyFeature:kFeatureAId 
           onComplete:^(NSString* purchasedFeature) 
{ 
    NSLog(@"Purchased: %@", purchasedFeature); 
} 
           onCancelled:^ 
{ 
    NSLog(@"User Cancelled Transaction"); 
}]; 

或可替代NSUserDefaults的,UIApplication的等。另一種方法可以看出,在MagicalRecord或在這裏與解析API:

// configure API credentials sometime during app boot 
[Parse setApplicationId:@"123456" 
       clientKey:@"123456"]; 

// sometime later 
PFObject *testObject = [PFObject objectWithClassName:@"TestObject"]; 
[testObject setObject:@"bar" forKey:@"foo"]; 
[testObject save]; 

有哪些這兩種方法的優缺點是什麼,其中一個比另一個更好?

無需檢索共享實例可以節省一些屏幕屬性(性能差異可能不相關),但是我是否以其他方式搞砸了自己,例如,可測試性?

謝謝!

回答

27

有實現方法有兩個不同的方法基於類的方法:

  • 使用從每個人隱藏類做單一實例,以及隱藏其背後的包裝類方法具有相同簽名的方法,或
  • 製作類方法是做好一切工作

第一個實現的含義是,一切都可以用一個單獨做,你可以隱藏單做:

  • 使用一個子類成爲可能
  • 在運行的中間切換的情況下很容易
  • 國家生活中的實例變量
  • 初始化遵循熟悉的模式

如果您去一個不使用單例的實現,你會依靠靜態變量來保持你的當前狀態。這是一個合理的選擇,但初始化模式變得不同(甚至可能使用了dispatch_once),如果不依賴某些醜陋的if條件,則無法在中間切換實現,並且使用子類變得更加棘手。

測試第一個實現比測試第二個實現要容易一些,因爲您可以提供一個單獨的實現來測試,也許通過後門;在基於靜態的實現中,這條路線不能被採用。總之,我將使用基於單例的解決方案,單例可以隱藏在提供對單例方法訪問的「外觀」之後。我不會使用所有狀態必須放置在靜態變量中的實現。

+1

很好的答案,謝謝! –

+0

很好的答案,但一個小例子將使它更容易理解。 – atulkhatri

7

單例方法的一個優點是,如果需要的話,允許其他實例變得微不足道。如果你採用類方法,那麼你就可以在沒有大量重構的情況下獲得。