有什么理由不在 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' 的行为现在会受到单例行为的影响。
另一个可能的问题是线程安全。在没有锁定的情况下从不同的线程访问单例时,可能会出现难以调试的问题。
总结
定义全局变量和使用单例时要小心。适当的照顾,应该不会出现很多问题。
对于 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' 的行为现在会受到单例行为的影响。
另一个可能的问题是线程安全。在没有锁定的情况下从不同的线程访问单例时,可能会出现难以调试的问题。
总结
定义全局变量和使用单例时要小心。适当的照顾,应该不会出现很多问题。