2012-11-02 57 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

单例方法的一个优点是,如果需要的话,允许其他实例变得微不足道。如果你采用类方法,那么你就可以在没有大量重构的情况下获得。