【问题标题】:Swift singleton vs. static properties/methodsSwift 单例与静态属性/方法
【发布时间】:2019-06-19 13:40:37
【问题描述】:

根据this blog postcurrently highest voted answerthis Stack Overflow question,后者又引用Apple's documentation,在现代Swift 中创建单例的最佳方法是:

class Singleton  {
   static let sharedInstance = Singleton()
}

虽然没有提到,但可能也需要 private init()

对我来说,更简单的替代方法是将所有属性和方法转换为 static,然后删除 sharedInstance 属性。

例如,假设我按照上面的建议编写了一个带有属性和方法的类,如下所示:

class Singleton {
  static let sharedInstance = Singleton("whatever")

  var myProperty: String

  func myMethod() {
    // ...
  }

  private init(_ myProperty) {
    self.myProperty = myProperty
  }
}

如果用户需要访问有问题的属性,他们会写Singleton.sharedInstance.myProperty,如果他们需要调用方法,他们会写Singleton.sharedInstance.myMethod()

我建议重写类如下:

class Singleton {
  static var myProperty: String = "whatever"

  static func myMethod() {
    // ...
  }
}

因此:在访问属性(仅Singleton.myProperty)和方法(Singleton.myMethod())时,需要更少的样板代码和更少的字符。

一个缺点是从类内部访问属性和方法需要完全拼写出来(Singleton.myPropertySingleton.myMethod()),而之前的解决方案只需要 myPropertymyMethod()

因此,对用户来说更容易一些(删除sharedInstance 部分),对类编写者来说更难一些(需要在所有访问之前添加Singleton.)。当面对有利于用户或类编写者的设计选择时,更好的选择是有利于用户,这似乎是合理的。

似乎没有其他人支持我提出的制作单例的方法,所以我觉得它一定有问题。有人能指出这是什么吗?

【问题讨论】:

    标签: swift static singleton


    【解决方案1】:

    对我来说,更简单的选择是将所有属性和方法转换为静态,并删除 sharedInstance 属性。

    这些不做同样的事情。推荐的方法实际上根本不是单例。这只是一个众所周知的例子。单例模式的概念是必须只有一个实例。共享实例模式的一致之处在于可以有多个实例,但您可能需要一个实例,并且您希望轻松访问它。

    共享实例的优点是它们并不神奇。它们只是实例。这意味着它们可以作为值传递。它们可以替换为其他配置不同的实例。它们更容易测试(因为它们可以传递给函数)。

    真正的单例是一种非常严格的模式,只有在绝对没有其他实例存在的情况下才应该使用它,通常是因为它们与某些外部唯一资源交互的方式会在存在多个实例时产生冲突(这很漂亮稀有的)。即使在这种情况下,在 Swift 中,您通常也应该将 init 设为私有,以防止创建额外的实例。

    如果你环顾一下 Cocoa,你会发现共享实例对于其他框架中的单例来说非常普遍,而且它非常强大。例如,有一个众所周知的NotificationCenter,叫做default,它可能是你唯一用过的。但是创建一个独立的私有NotificationCenter 是完全有效的(我实际上已经在生产代码中这样做了)。

    UIDevice.current 是您访问设备的方式,而不是静态方法,这一事实为可以处理多个设备的新 API 提供了可能性(它也有助于单元测试)。在最早的 iOS 版本中,唯一的 UIScreen.main,将其设为单例可能是有意义的。但是因为苹果没有,所以在4.3加入镜像的时候,就简单的说下二屏了(UIScreen.mirrored)。通常,您应该很慢地认为只能是其中之一。

    【讨论】:

    • 关于单例与知名实例的观点,我会考虑哪个更适合我的情况。假设我确实想使用单例,那么具有私有 init() 的类与所有属性和方法都是静态的类相比如何?
    • 私有init 允许将来扩展(例如,以后公开init,或创建子类),并且与所有其他对象的接口保持一致。调用者不必猜测某个东西是静态方法还是实例方法。除非它是 type 的基础(即工厂或默认值),否则方法应该在实例上。
    • +1 FWIW,我理解你在单例的严格定义和 their discussion of the pattern 中概述的 Apple 的较弱定义之间的区别。但他们反复将这种模式视为单例(例如,URLSession.shared 被称为“共享单例”,尽管我们一直实例化自己的 URLSession 实例)。
    • 是的,多年来,对名称的草率导致了各种不良模式。很多人抄了苹果过于复杂的“严格执行”的例子,因为他们没有仔细阅读第一段:developer.apple.com/library/archive/documentation/Cocoa/…
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-11
    • 2011-03-26
    • 2012-08-30
    • 1970-01-01
    • 2012-11-12
    • 2011-03-02
    • 2011-05-17
    相关资源
    最近更新 更多