有什么理由不在 Swift 中使用单例 "variable"?

Any reason not use use a singleton "variable" in Swift?

对于 2015 年 9 月,以下是您在 Swift 中创建单身人士的具体方式:

public class Model
    {
    static let shared = Model()
    // ( for ocd friends ... private init() {} )
    
    func test()->Double { print("yo") }
    }

然后在其他地方...

blah blah
Model.shared.test()

没问题。

不过。我加这个小东西...

public let model = Model.shared
public class Model
    {
    static let shared = Model()
    
    func test()->Double { print("yo") }
    }

然后,您只需在整个项目范围内执行以下操作:

blah blah
model.test()

惯用语:

代码中处处可见 Model.shared.blah()

“我的”成语:

代码中处处可见 model.blah()

所以,这让一切看起来都很漂亮!

这就是一个“类宏”的成语。

这样做的唯一目的是让代码看起来更漂亮。

在整个项目中将 ImportantSystem.SharedImportantSystem 的外观简化为 importantSystem.

谁能看出这个成语有什么问题吗?

问题可以是技术的、文体的或任何其他类别的,只要它们确实很深。

作为一个随机示例,这里有一篇“Swift 中关于单例的文章”恰好也提出了这个想法:https://theswiftdev.com/swift-singleton-design-pattern/

我看不出这种方法有任何缺点:

  • 您可以为程序的不同部分使用不同的变量(-> 我猜如果您不喜欢,就不要填满命名空间)
  • 它简短、漂亮、易于使用并且读起来很有道理。 Model.shared.test()仔细想想也没什么意义,你就是想调用test,我刚需要一个函数为什么还要调用shared
  • 它使用 Swift 的惰性全局命名空间: class 在您第一次使用时分配并初始化;如果您从不使用它,它甚至不会 alloced/inited.

总的来说,抛开正在讨论的确切习语,关于单例的使用:

  • 回想一下,当然,您可以只定义 let model = Model() 来简单地创建一个普通的全局(与单身人士无关)。
  • 对于 Swift 单例,有讨论认为你想添加一个 private init() {} 到你的 class,这样它只被初始化一次(注​​意 init 仍然可以在同一个文件中调用)。
  • 当然,一般来说,在考虑使用单例时,如果你真的不需要状态和 class 实例本身,你可以简单地使用静态 functions/properties 代替。在只需要静态方法的情况下使用单例(例如 "calculation-like" 函数)是一个常见的错误。

在功能上,它们非常相似,但我建议使用 Model.shared 语法,因为无论你在哪里使用它,它都非常清楚,你正在处理一个单例,而如果你只是model 全局浮动在那里,不清楚你在处理什么。

此外,对于全局变量(特别是简单名称,如 "model"),您可能会遇到一些具有类似命名变量的未来 class 并意外引用错误的变量。

有关全局变量、单例变量和其他模式的一般注意事项的讨论,请参阅 Global Variables Are Bad,尽管标题相当领先,但它提出了一个清醒的讨论,有一些有趣的链接并提供了替代方案。


顺便说一句,对于您的 "OCD friends"(我想我必须算上我自己,因为我认为这是最佳实践),不仅会将 init 声明为 private ,但您可能会将整个 class 声明为 final,以避免 subclassing(此时它对 shared 引用的内容变得模棱两可)。

使用此方法时需要注意以下几点:

全局变量

一个全局变量本身没什么大不了的,但是如果你有很多全局变量,你可能会遇到自动补全的问题,因为它会一直提示这些全局变量。

全局变量的另一个问题是您的应用程序中的另一个模块(由您或其他人编写)可以定义相同的全局变量。当一起使用这 2 个模块时,这会导致问题。这可以通过使用前缀来解决,例如应用程序的首字母。

使用全局变量是generally considered bad practice

单例模式

单例在使用控制器或存储库时很有用。它一旦被创建,它就会创建它所依赖的一切。只能有一个控制器,它只打开一个到数据库的连接。这在处理需要从整个应用程序访问的资源或变量时避免了很多麻烦。

但是也有缺点,例如可测试性。当 class 使用单例时,class' 的行为现在会受到单例行为的影响。

另一个可能的问题是线程安全。在没有锁定的情况下从不同的线程访问单例时,可能会出现难以调试的问题。

总结

定义全局变量和使用单例时要小心。适当的照顾,应该不会出现很多问题。