我这里有一个很常见的情况。多年来,我一直没有发现我所做的事情是否符合行业标准。考虑一个连接到数据库的应用程序,但连接字符串不是存储在某些文件/设置中,而是作为命令行参数传递在启动时或在应用程序启动时浏览数据库。

那么有必要将该连接字符串保存在应用程序范围内的某个位置。我见过的最常见的方法是使用模块或全局类,使用 get/set 方法来保存连接字符串。我会做的另一种方法是使用 Singleton。无论哪种选择,我的 DAL 都可以在需要时通过 GetConnectionString 方法访问连接字符串。

有更好的方法吗?

更新: 我没有配置文件,即使有,我也需要在应用程序实例的生命周期内读取一次连接字符串。你能详细说明一下“将它注入到任何类中”部分吗

有帮助吗?

解决方案

在一般的全局状态下,无论是全局类还是单例,都应该尽可能避免。

理想的解决方案是让您的应用程序从配置中加载连接字符串并 注入 它进入任何需要它的类。根据您的应用程序的大小, 国际奥委会 类似容器 统一 或者 温莎城堡 可以提供帮助,但肯定不是解决方案的必需部分。

如果这不是一个选择,并且您被迫维护全局状态(由于现有的代码库或其他原因),我不知道您建议的两种方法之间存在巨大差异。

更新: 只是为了澄清一下,暂时忘记有关 IoC 容器的所有内容,“注入”只是“作为参数传递”的一种奇特方式(或者传递给类的构造函数,或者通过属性,或者其他方式)。

数据访问类不必要求连接字符串(来自某种全局或单例),而是通过构造函数或属性传入。

更新#2: 我认为对于这种方法的含义仍然存在一些误解。

它基本上取决于您的数据访问类是否如下所示:

public class DataAccessClass
{
    public DataAccessClass()
    {
        _connString = SomeStaticThing.GetConnectionString();
    }
}

或者

public class DataAccessClass
{
    public DataAccessClass(string connString)
    {
        _connString = connString;
    }
}

这些 文章 (事实上​​,该博客中的许多文章)详细说明了后者优于前者的许多原因(尤其是因为前者几乎不可能进行单元测试)。

是的,在 某个地方 首先必须有一些静态人员负责获取连接字符串,但关键是您对静态方法的依赖仅限于该一个点(这可能是该过程中的 Main 方法)引导您的应用程序),而不是散布在整个代码库中。

其他提示

很高兴看到如此简单的问题有这么多创造性的解决方案;-)

来自OP问题的显着事实:

  1. 连接字符串在命令行上传递
  2. 许多其他组件可能需要使用连接字符串

所以, 没有办法绕过静态元素的使用;无论它是全局变量(在 .NET 中确实很难做到,没有封闭类)、静态类还是单例,这并不重要。最短路径解决方案是由处理命令行的 Program 类初始化的静态类。

所有其他解决方案仍然需要静态访问传入的连接字符串, ,尽管它们可能会将其隐藏在一层或多层间接层后面。

我并不是说您不想用更奇特的东西来装饰基本解决方案,但这是没有必要的,并且它不会消除连接字符串的基本静态/全局性质 如上所述.

如果你要存储是一个字符串(可能连同一堆其他的全局应用程序设置),我只想用一个静态类与一群属性来容纳所有。单身是更多的代码和维护工作,但它是在这种情况下不必要的工作,因为你的属性的类是不会做任何事情;刚装东西。

当然,有一种方法。首先,加快速度上依赖注入和类似的技术,并阅读有关的服务层因为那是什么您这里需要。

至于服务层而言,你需要某种配置服务,这将是您的应用程序的部分将用于配置信息查询模块 - 连接字符串的URI等:

interface IConfigurationService
    string ConnectionString
    bool IntegratedSecurity
    bool EncryptProfiles

这应该是非常简单的,有一个只有在你的系统IConfigurationService的实例,但是这与选择的DI容器来实现,而不是与Singleton模式。

接下来,所有的DAL服务将获取到IConfigurationService参考:

class FooDal : IFooDal
    IConfigurationService ConfigurationService

,以便他们现在可以使用IConfigurationService.ConnectionString来获取连接字符串的保持。

这取决于。

请记住,单例:

  • 强制该类只存在一个实例,并且
  • 提供全球访问

全局仅提供全局访问,但不保证实例化的数量。

当然,最后的选择是使用局部变量。也就是说,将配置信息作为参数传递给构造函数或任何需要的地方。

在前两者之间进行选择应该比较容易。如果该类存在两个实例,这会是一场灾难吗?我想说可能不会。我可能想实例化我自己的配置类,以便为应用程序的一个特定组件提供单独的选项,或者初始化我的单元测试。

极少数情况下您 需要 以保证只有一个实例存在。因此,全局可能是比单例更好的选择。

本地和全局之间的选择更加棘手。通常最好避免全局可变状态。 不可变的 状态不是一个问题,并且不会导致与全局可变状态相同的同步/并发/可伸缩性问题。

但通常情况下,最好将其作为局部变量传递给需要它的组件。这可以手动完成,只需将其传递给需要数据库访问的对象的构造函数,或者在某种程度上可以使用 IoC 容器自动完成。

但无论如何,如果它不是全局的,那么您的代码就会变得更加通用,并且更加可移植。如果它隐藏了对类和全局数据的依赖关系 必须 存在才能使代码正常工作,那么它就不能轻易地在其他项目中使用,或者如果您对整个代码库进行了过多的重构。

单元测试也变得更加困难,因为除非存在一些我们希望在测试中排除的外部数据,否则代码甚至无法编译。

作为@Anton说,你需要有一个公开类似

的接口
interface IConfigurationService
    string ConnectionString

然后,每当你的类的人需要你的连接字符串,你为它提供在包含有效的字符串建设IConfigurationService的实现。你需要找到一个有效的地方创建您的实现,当你的应用程序启动(可能是时间,你会得到你的数据库ADRESS),并把它转嫁给类需要它。

即使它可能看起来很多工作相比,单身或全球,这将降低耦合在你的代码,因此提高了可重用性,使单元测试更加简单,并且是非常简单的,一旦你说服自己,全局的(大部分)邪: )

由于之前mentionned,有IoC容器,将提供一个框架,要做到这一点,但它可能在你的情况是矫枉过正,加上其不错的让工作提高到一个“魔盒”前使用该模式为自己

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top