【问题标题】:Why use Singletons?为什么使用单例?
【发布时间】:2013-03-03 07:40:46
【问题描述】:

好的,我知道这个问题可能看起来无关紧要或过于基本,但是 - 因为我一直想知道我在做什么以及我为什么要这样做,如果它符合我的设计 - 请阐明一下。

所以,这就是我需要的:

  • 假设我们有一堂课
  • 我们想在几乎任何地方使用它的方法
  • 我决定使用类方法和伪全局实例,而不是传递一个对象

所以,假设我们有一个名为“MyDocumentManager”的类。


这是我通常做的:

+ (MyDocumentManager*)documentManager
{
     MyDocumentManager* newDocumentManager = [[MyDocumentManager alloc] init];

     if (newDocumentManager)
     {
          // initialize that new document manager
     }
     return newDocumentManager;
}

然后像这样使用它:

[[MyDocumentManager documentManager] someMethod];

但是,我通常看到有人提出类似的建议:

+ (MyDocumentManager*)sharedManager
{
    static dispatch_once_t pred;
    static MyDocumentManager *sharedManager;
    dispatch_once(&pred, ^{
        sharedManager = [[MyDocumentManager alloc] init];
    });
    return sharedManager;
}

所以,这是我的问题:

  • 是一回事吗?
  • 如果不是,有什么区别?
  • 其方法的优点/缺点是什么? (在内存/速度/等方面)
  • 我应该使用哪一个?为什么?
  • 它们都符合我的需要吗?

【问题讨论】:

  • @pst 你说得有道理;但是,我的问题标题似乎仍然适合我:问题不仅与实现有关,还与单例的本质/使用有关。
  • 这是两个问题 - 后者已经在 SO 上进行了很好的讨论。附言我认为您在第一个示例中错过了static
  • @pst 你的意思是在 my 代码中?我没有错过任何东西。 (而且我没有提到它是一个单例 - 只是添加了我通常使用的代码......事实证明它是错误的......)

标签: objective-c cocoa oop class singleton


【解决方案1】:

是一样的吗?

没有。

如果不是,有什么区别?

您所拥有的并没有实现单例,因为它会在每次函数调用时分配一个新的类实例。而是称为工厂方法。单例的定义是某个类方法总是返回该类的相同实例。

我应该使用哪一个?为什么?

您通常应该避免使用单例,因为它通常被认为是不好的做法,尽管在某些情况下使用它们很方便。例如,如果你有一个使用封装数据的类,但你只需要准类级别的方法,那么最好实现一个带有适当放置的实例变量的单例,而不是实现类方法和大量的全局/静态变量(这是因为在Objective-C,类不能有成员变量,只有对象)。

它们都符合我的需要吗?

你决定。

【讨论】:

  • 好的,我们以这种情况为例:我需要几个全局可访问方法作用于一些数据(在使用方法之前必须进行一些初始化 - 但是实际的“核心”在运行时是不可变的)。 会建议什么?单身是个坏主意吗?
  • @Dr.Kameleon “一些数据”是一个特定的数据吗?如果是这样,单例可能是一个不错的选择。如果不是(即您可以拥有多个),那么您实现的工厂方法会更合适。
  • 让我更具体一点(这仍然是一个例子):我们有一个专门的类来处理应用程序设置。当应用程序启动时,会加载设置。每次我想从设置中更新/设置/删除某些选项时,我都使用 Settings 类的方法(将数据存储到磁盘/从磁盘检索数据)。这个案子怎么办?
  • @Dr.Kameleon 在这种情况下可以使用单例,但我怀疑你仍然可以避免它......这个类是否类似于NSUserDefaults
  • 我告诉过你 - 我只是想给你一个例子。我在各种各样的情况下使用相同的模式(在这种情况下,我实际上更喜欢一些更老式的全局变量的东西 - 我知道,不是最好的东西,但这就是感觉......哈哈)。老实说,如果我不尝试对 ObjC 友好,我很容易将它们中的大多数视为全局 C 函数。
【解决方案2】:

您在“我通常做什么”中粘贴的代码已损坏。它不返回单例。每次调用它时它都会返回一个全新的对象(如果这不是 ARC,那么它也会泄漏它)。

您按照人们的建议粘贴的代码是正确的代码。它不仅每次都返回一个共享对象,没有泄漏,而且它也是线程安全的(就对象的初始化而言;它没有说明对象的使用是否是线程安全的)。

【讨论】:

  • 我没说它单身。我只是说明了我通常在做什么。 (是的,它支持 ARC)。
  • @Dr.Kameleon:命名+[MyDocumentManager documentManager] 通常意味着它返回一个单例。实际上,您的“常规”方法几乎与仅调用 +new 相同,只是您有初始化代码,无论出于何种原因,您都选择不输入 -init
猜你喜欢
  • 2011-10-16
  • 1970-01-01
  • 1970-01-01
  • 2011-02-27
  • 2018-01-12
  • 1970-01-01
  • 2011-10-23
  • 2011-02-15
  • 2018-06-13
相关资源
最近更新 更多