问题描述
最近与Objective-C和其中写了各种图书馆合作,我注意到了两个非常受欢迎的Singleton模式.一个版本获取Singleton实例,并称其实例方法和其他版本仅揭示类方法,并且永远不会给您一个实例.所有人的目的都是抽象访问单个资源(Storekit,Coredata,Parse API等).例如,这是Mkstorekit中使用的前一种方法:
// 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或Parse 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];
这两种方法中有哪些利弊,其中一种比另一种更好?
不必检索共享的实例可以节省某些屏幕遗产(性能差异可能无关),但是我是在其他方式上搞砸自己,例如,可测试性吗?
谢谢!
推荐答案
有两种不同的方法来基于类方法实现该方法:
- 使用每个人隐藏的类制作单身实例,并将其方法隐藏在具有相同签名的包装类方法后面,或者
- 制作完成所有工作的类方法
第一个实现的含义是您可以使用单身人士来做的所有事情,您可以使用隐藏的Singleton:
- 使用子类成为可能性
- 在运行中间切换实例很容易
- 国家生活在实例上
- 初始化遵循熟悉的模式
如果您选择不使用单身人士的实现,则您将依靠静态变量来保持当前状态.这是一个合法的选择,但是初始化模式变得不同(甚至可能使用dispatch_once),如果不依赖某些丑陋的if条件,则不能切换中间的实现,并且使用子类变得更加棘手.
测试第一个实现比测试第二个实现要容易得多,因为您可以通过后门提供单独的Singleton进行测试的实现;通过基于静态的实现,无法采用此路线.
总而言之,我将使用基于单顿的解决方案,而单身人士(Singleton)可选地隐藏在"立面"后面,该解决方案可访问Singleton的方法.我不会使用必须将所有状态放在静态变量中的实现.
其他推荐答案
单例方法的一个优点是,如果需要的话,允许其他实例变得琐碎.如果您采用类方法方法,那就是您没有很多重构的一切.
问题描述
While recently working with Objective-C and various libraries written in it, I've noticed two really popular singleton patterns. One version fetches the singleton instance and calls its instance methods and other version only exposes class methods and never gives you an instance to work with. All have the purpose of abstracting access to a single resource (StoreKit, CoreData, Parse API etc.). For example, here's the former approach used in MKStoreKit:
// 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"); }];
or alternatively NSUserDefaults, UIApplication etc.. The other approach can be seen in MagicalRecord or here with Parse 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];
What are some pros and cons of the two approaches and is one of them fundamentally better than the other?
Not having to retrieve the shared instance saves some screen estate (the performance difference is likely irrelevant), but am I screwing myself in some other way, for example, testability-wise?
Thanks!
推荐答案
There are two different ways to implement the approach based on class methods:
- Make a singleton instance using a class hidden from everybody, and hide its methods behind wrapper class methods with identical signatures, or
- Make class methods that do all the work
The implications of the first implementation are that everything you can do with a singleton, you can do with the hidden singleton:
- using a subclass becomes a possibility
- switching the instance in the middle of the run is easy
- the state lives in instance variables
- initialization follows the familiar pattern
If you go for an implementation that does not use a singleton, you would be relying on static variables to keep your current state. That is a legitimate choice, but the initialization pattern becomes different (perhaps even using a dispatch_once), you cannot switch the implementation in the middle without relying on some ugly if conditions, and using a subclass becomes a lot more tricky.
Testing the first implementation is somewhat easier than testing the second one, because you can provide a separate implementation of the singleton for testing, perhaps through the back door; with a static-based implementation, this route cannot be taken.
To summarize, I would use a singleton-based solution, with the singleton optionally hidden behind a "facade" that provides access to singleton's methods. I would not use an implementation where all state must be placed in static variables.
其他推荐答案
One advantage of the singleton approach is that it becomes trivial to allow other instances if you need to. If you take the class method approach, that's all you get without a lot of refactoring.