首页 > 解决方案 > 将数据库连接用作静态是一种好习惯吗?

问题描述

我正在为我的 iOS 应用程序使用SQLite.swift框架。我有DatabaseService一个创建数据库连接并执行所有CURD操作的类。我正在实例化这个类并在每个控制器上创建一个连接,但最近我将数据库变量更改为static并为所有控制器创建一次连接。我不确定这是否是一个好习惯。这是我执行此操作的方式:

static var db: Connection?

init() {
    if DatabaseService.db != nil {
        return
    }
    let path = NSSearchPathForDirectoriesInDomains(
        .documentDirectory, .userDomainMask, true
        ).first!
    do {
        let fileManager = FileManager()
        try fileManager.copyfileToUserDocumentDirectory(forResource: "db", ofType: "sqlite3")

        // Empty database will be created if file does not exist
        DatabaseService.db = try? Connection("\(path)/db.sqlite3")

        print("Connection successful")
    } catch let error {
        print("Unable to connect with the database. \(error)")
    }
}

标签: iosswiftsqlite.swift

解决方案


我想真正的答案是:如果你知道自己在做什么,并且对如何安全地做这件事有很好的把握,那么当然可以。

但既然你问:我的答案是否定的。

您在此处显示的静态变量是单例模式,如果您在任何地方都使用它的话。单例模式通常感觉是正确的做法,但是当您开始添加线程并想要使用不同的数据提供者时,事情开始变得有问题、更复杂和难看。你最好使用工厂模式的依赖注入,使用你只实例化一次的对象。

这样做真的不需要更多的代码。当您想要注入它时(编译时或运行时),选择就变成了,而 Swift 使这一切变得非常容易。如果您想通过示例进行编辑,请告诉我。预先以这种方式执行此操作需要更多代码,但从长远来看,对于大多数情况,它会为您节省很多心痛。做一些关于单例的利弊的研究。大多数人都同意在大多数情况下这是一个坏主意。

我将添加我强烈推荐的书中的一段:

主要问题可能是由全局状态引起的,例如,在您的被测单元中使用单例或静态成员。Singleton 不仅增加了软件单元之间的耦合。他们还经常拥有一个绕过单元测试独立性的全局状态。例如,如果某个全局状态是成功测试的先决条件,但之前的测试已经改变了该全局状态,那么它可能会导致严重的问题。尤其是在遗留系统中,这些系统经常充斥着单例,这就引出了一个问题:我如何才能摆脱对这些单例的所有讨厌的依赖,并使我的代码更好地可测试?嗯,这是我讨论的一个重要问题......

这本书还继续引用了对标志性书籍设计模式作者的采访,作者基本上说他们不介意放弃单例模式,因为它从未被正确使用。

一本关于抽象设计模式的标志性和有影响力的书的作者开玩笑(我认为这是一个笑话)关于从他们的书的新修订版本中删除单例设计模式......

也许真正的答案真的永远是否定的。


推荐阅读