使用单件设计模式时,首选哪种结构?为什么?

时间:2011-10-26 14:51:01

标签: c# asp.net design-patterns mvp

除了“what is so bad about singletons”:-)之外,我还有一个ASP.NET Web应用程序,它在业务逻辑层使用单例,因此:

public class MyBusinessService
{
    private static MyBusinessService mInstance = null;

    public static MyBusinessService Instance
    {
        get { return mInstance; }
    }

    static MyBusinessService()
    {
        mInstance = new MyBusinessService();
    }
}

我们主要将它们用于Model View Presenter架构中的依赖项。

它们还可以通过两种方式之一跨业务逻辑类使用。首先以下列方式:

var myService = new MyBusinessService();
myService.DoSomething();
myService.DoSomethingElse();

或者,它可以按以下方式使用:

MyBusinessService.Instance.DoSomething();
MyBusinessService.Instance.DoSomethingElse();

哪种结构首选,为什么?我对单身模式本身的好坏不感兴趣。

更新: 好吧,这个问题似乎很受欢迎。我猜这是一个准单身人士。最糟糕的是两个世界!我真的不想重构模式/反模式/代码地狱。我更感兴趣的是了解所描述的两种用法的影响。

我们的视图(ASP.NET页面)如下所示:

var presenter = new SomeViewPresenter(this, MyBusinessService.Instance);

但也可以实现为:

var presenter = new SomeViewPresenter(this, new MyBusinessService());

在这种情况下,我更喜欢前者。注:单词的使用和上面的错误用法是可以理解的,但是正如代码所示,这两个原始选项的结果是什么?

6 个答案:

答案 0 :(得分:2)

您的班级不是没有私人构造函数的单身人士

所以如果你添加一个私有构造函数

private MyBusinessService()
{
}

然后你被限制在第二次使用,它是一个单身类

答案 1 :(得分:2)

后者是首选,因为前者的行为不像单身人士 - 你实例化一个新实例而没有任何保护来阻止多个实例存在。

如果你把这些警卫放在适当位置,后者就是你可能最终得到的代码。您也不需要一直使用该属性:

var service = MyBusinessService.Instance;
service.This();
service.That();

我也对ASP.NET中的静态有一些怀疑,这是来自WinForms开发人员: - )

答案 2 :(得分:1)

第一个可以说是首选,因为它不是单身人士。既然你想把关于单身人士的论点放在一边,那么第二个就是首选,因为它是。

答案 3 :(得分:1)

通常,只要您希望将程序限制为具有类的单个实例,就应该使用单例模式。应该使用它而不是简单地将所有内容标记为静态,因为当你这样做时,不可能将该类作为一个实例(例如将它作为参数传递给类/方法),这使得遵循良好的设计模式,如依赖性倒置原则很难或不可能。

你对MyBusinessService“新”起来的能力击败了单身人士的目的。如果您希望能够随意创建新实例,那么只需将其设为普通实例类即可。如果要限制为一个实例,那么根据定义,您不应该有权访问默认构造函数。

以下是您的课程看起来像真正的单身人士:

public class MyBusinessService
{
    private static MyBusinessService mInstance = null;

    public static MyBusinessService Instance
    {
        get { return mInstance; }
    }

    static MyBusinessService()
    {
        mInstance = new MyBusinessService();
    }

    private MyBusinessService() {}
}

添加标记为private的默认实例构造函数意味着var myService = new MyBusinessService();不会从MyBusinessService范围之外编译(从而限制其用于静态构造函数)。

还有一件事;如果MyBusinessService可能不会在每种情况下都使用,或者创建起来很昂贵,那么你可能会考虑让它变得懒惰。默认情况下,静态构造函数在启动时运行;但是,静态成员在首次引用之前不会被评估。因此,您可以像这样设置您的类,并且在程序知道它需要一个之前不会创建MyBusinessService实例:

public class MyBusinessService
{
    //the instantiation will not happen until the Instance property is called
    private static readonly MyBusinessService mInstance = new MyBusinessService();

    public static MyBusinessService Instance
    {
        get { return mInstance; }
    }

    private MyBusinessService() {}
}

答案 4 :(得分:0)

上面两个选项是完全不同的。第一个选项将调用默认的ctor,但第二个选项不会。这可能是也可能不是问题,具体取决于您是否需要初始化任何实例成员。

如果您不需要基于实例的ctor,我的偏好是选项#2。这真的取决于你如何使用它。

答案 5 :(得分:0)

在这两个选项中,第二个选项是首选的,因为它的行为类似于真正的单身人士。

有关如何实施单身人士的明确指南,请参阅http://csharpindepth.com/Articles/General/Singleton.aspx

你会发现要记住几个方面(如性能,懒惰,异常,线程安全等)。