.NET中的Global vs Singleton

时间:2009-02-02 17:23:00

标签: .net singleton global

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

有必要将该连接字符串保存在应用范围内的某个位置。我看到它最常见的方法是使用get / set方法保存连接字符串的模块或全局类。我会这样做的另一种方法是使用Singleton。 当需要通过GetConnectionString方法时,我的DAL可以访问连接字符串。

有更好的方法吗?

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

6 个答案:

答案 0 :(得分:8)

在一般的全球状态中,无论是全球级还是单身,都应该尽可能避免。

理想的解决方案是让您的应用程序从配置中加载连接字符串,并将inject加载到需要它的任何类中。根据应用程序的大小,IoCUnityCastle Windsor容器可以提供帮助,但肯定不是解决方案的必需部分。

如果这不是一个选项,并且你因为现有的代码库或其他原因而无法保持全局状态,我不知道你建议的两种方法之间存在巨大差异。

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

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

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

这主要取决于您的数据访问类是否类似:

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

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

These articles(事实上,该博客中的许多文章)详细说明了为什么后者比前者更好的原因(尤其是因为前者几乎不可能单位检验)。

是的,在某个地方,首先必须要有一些静态的人负责抓取连接字符串,但关键是你对静态方法的依赖只限于那个一个位置(在引导应用程序的过程中可能会成为您的主要方法),而不是遍布整个代码库。

答案 1 :(得分:5)

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

来自OP问题的显着事实:

  1. 连接字符串在命令行上传递
  2. 许多其他组件可能需要使用connect-string
  3. 所以,无法使用静态元素;它是一个全局变量(在.NET中很难做到,真的,没有封闭类),静态类或单例确实无关紧要。最短路径解决方案是由处理命令行的Program类初始化的静态类。

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

    我并不是说你不想用更好的东西打扮基本解决方案,但这不是必要的,它并没有消除连接字符串的基本静态/全局特性。描述

答案 2 :(得分:4)

如果您要存储的只是一个字符串(可能还有一堆其他全局应用程序设置),我只会使用一个带有一堆属性的静态类来保存所有这些。单身是更多的代码&维护工作,但在这种情况下这是不必要的工作,因为你的属性类不会做任何事情;抱着东西。

答案 3 :(得分:2)

当然有办法。首先,快速了解dependency injection和类似的技巧,并阅读service layer,因为这就是你需要的。

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

interface IConfigurationService
    string ConnectionString
    bool IntegratedSecurity
    bool EncryptProfiles

在您的系统中只有一个IConfigurationService实例应该非常简单,但这是通过选择的DI容器实现的,而不是使用Singleton模式。

接下来,您的所有DAL服务都会获得对IConfigurationService

的引用
class FooDal : IFooDal
    IConfigurationService ConfigurationService

这样他们现在可以使用IConfigurationService.ConnectionString来获取连接字符串。

答案 4 :(得分:1)

这取决于。

请记住单身人士:

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

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

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

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

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

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

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

但无论如何,如果它不是全局的,那么你的代码会变得更通用,更便携。如果它对必须存在的类和全局数据有隐藏的依赖关系,那么它就不能轻易地在其他项目中使用,或者如果你过多地重构整个代码库。

单元测试也变得更加困难,因为代码甚至不会编译,除非存在一些我们理想的离开测试的外部数据。

答案 5 :(得分:0)