使用单例作为数据管理器类是不好的吗?

7
我经常制作需要存储数据的应用程序,并且这些数据在整个程序中都被使用。虽然它不多,但我通常使用NSUserDefaults来加载/保存这些数据。但是,保存/加载代码以及打包/解包数据需要占用空间,我认为将此代码移动到全局单例内的可重用方法中是一个好主意。看起来效果不错。
即便如此,最近我读了很多有关单例和全局对象的问题,开始有所疑虑。人们经常说,单例的使用几乎总是设计不良的表现。在大多数情况下,我不太同意(我认为像这样的简单使用是一种良好的设计模式),但我绝对不是这个问题的专家。
那么,即使像这样简单地使用单例也不好吗?如果是,有什么更好的替代方案?

1
不错,一点也不错。请记住,由苹果提供的许多iOS SDK类都是作为单例实现的。这并不意味着苹果代码自动就是好代码,但它确实强烈暗示单例模式并非没有可取之处。 - aroth
1个回答

5
我并不认为单例模式是邪恶的。它们有时可能被过度使用,但在某些情况下,它们非常适合工作。在一些应用程序中,拥有某种通用数据管理器是有意义的。单例模式在 SDK 中被广泛使用(应用程序代理、共享管理器、默认中心等等)。大多数情况下,它们不是“纯”单例模式,也就是说,你可以访问一个共享实例,但如果必要,也可以创建新的实例。
你需要问自己的问题是:是否有必要随时从任何地方访问数据管理器的单个实例,如果没有,那么可能不需要单例模式。然而,如果你将在多线程环境中使用单例模式,则需要担心竞态条件(一个线程修改资源而另一个正在访问它),文档对如何在 Cocoa 中实现最佳方式有很好的解释。
让我举个例子来解释一下 - 我正在使用我写的游戏中的一些代码。假设你有一个 GameMap 类和一个 Tile 类。GameMap 表示一个 2 维网格的 Tile 对象。
GameMap *gameMap = [[GameMap alloc] init];
NSArray *theTiles = gameMap.tiles;
GameMap的实例拥有瓦片网格,并在创建游戏地图时创建瓦片。不需要单例模式。
你可能会说“但是我一次只能有一个GameMap,那有什么大不了的?” 那要是加载保存的游戏或者加载新关卡呢?那就变得很简单了:
// In whatever class object owns the game map
self.gameMap = [[GameMap alloc] initWithSaveData:saveData];

结论:创建一个类的实例,它具有管理其他事物实例的代码。尽可能少地使用全局变量,这样您的代码将更具可扩展性和可维护性。

谢谢,这基本上也是我的观点。我只是需要一点确认,单例模式并不完全是邪恶的,因为在我所阅读的所有资料中,它似乎是一个必须尽量避免的东西。 - Alexis King
好的,很高兴能帮忙。我已经表达了我的观点。就像这样,酒精据说对健康有害,但适量饮用是可以的。在这里也是一样的。 - Srikar Appalaraju

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接