C#中的静态类与单体模式有什么区别?

131 阅读5分钟

在C#中,静态类与单体模式之间的区别是什么?

发现单体设计模式和C#类上的静态关键字在存储普通数据方面的区别。

在.NET框架中用C#开发应用程序时,你可以在两个单一的、共享的类实例之间进行选择。你决定使用静态关键字还是单体设计模式,取决于几个因素,下面的文章将概述这些因素。

静态类和单体模式的主要区别

简单地说,单子是一种模式,而静态类是一个关键字。这意味着你可以用单子在应用程序的整个生命周期内创建一个持久的实例。单子的好处是,单个实例可以作为其他方法的参数使用。另一方面,静态类只允许静态方法,不能作为参数传递。

其他主要区别包括:

  • 单子可以继承其他类,实现接口并允许继承,这使它们比静态类更灵活。

  • 你可以异步或懒惰地实现单子,而且.NET框架的CLR可以自动加载它。

  • 单元遵循面向对象的原则,让你以多态的方式处理它们,而不强迫用户假设只有一个实例。

  • 单元可以弃置,但静态类却不能。

  • 静态类存储在堆栈中,而单子则存储在堆中。

  • 单元可以克隆,而静态类不可以。

  • 单子可以有一个私有构造函数。

单子模式

大多数开发者同意单子设计模式是理想的解决方案。它们可以让你设计出只需要一个实例的类,比如经理类,用于缓存、线程池和日志。它们也非常适用于管理共享资源,如打印机的线程,在这里你需要避免对单一资源的冲突请求。

下面是我以前使用过的一个单子的实现。正如你所知,单子是一种高效、优雅的单实例对象。它的主要特征之一是它有一个静态属性,你必须访问这个静态属性来获得对象的引用。

/// <summary>/// Sample singleton object./// </summary>public sealed class SiteStructure{    /// <summary>    /// Possible an expensive resource we need to only store in one place.    /// </summary>    object[] _data = new object[10];    /// <summary>    /// Allocate ourselves. We have a private constructor, so no one else can.    /// </summary>    static readonly SiteStructure _instance = new SiteStructure();    /// <summary>    /// Access SiteStructure.Instance to get the singleton object.    /// Then call methods on that instance.    /// </summary>    public static SiteStructure Instance    {        get { return _instance; }    }    /// <summary>    /// This is a private constructor, meaning no outsides have access.    /// </summary>    private SiteStructure()    {        // Initialize members, etc. here.    }}

什么是静态类?

静态类是一个不能被实例化的,但也不需要你为每个新对象创建实例。它们消耗的资源更少,而且你不需要在内存中重复相同的类。这使得它成为一个方便的容器,用于专门操作输出参数的方法集,而不需要设置或获取任何内部实例字段。如果你只需要一个有几个实用方法的实用类,静态类的简单实现可以提高应用程序的性能,使其成为更好的选择。

单子模式相比,它的主要缺点是,一旦类被静态关键字装饰,你就不能改变它的行为方式。然而,单子模式的优势并没有结束。让我们来看看这两个类实例的主要区别。

静态类实例

在下面的例子中,看看我是如何在类和构造函数上使用静态关键字的。静态类可能不那么费事,但单子实例有很多重要的优势,我们将在这个代码块之后看一看。

/// <summary>/// Static class example. Pay heed to the static keywords./// </summary>static public class SiteStatic{    /// <summary>    /// The data must be a static member in this example.    /// </summary>    static object[] _data = new object[10];    /// <summary>    /// C# doesn't define when this constructor is run, but it will     /// be run right before it is used most likely.    /// </summary>    static SiteStatic()    {        // Initialize all of our static members.    }}

你可以使用静态类来存储单实例、全局数据。类可以在任何时候被初始化,但根据我的经验,它的初始化懒惰的--换句话说,在最后可能的时刻。因此,通过使用静态类,你可能会失去对类的确切行为的控制。

行动中的单体优势

单子保留了传统的类方法,不要求你在任何地方使用静态关键字。它们一开始可能对实现有更高的要求,但它们大大简化了你的程序的结构。与静态类不同的是,它可以作为参数或对象使用单子

// We want to call a function with this structure as an object.// Get a reference from the Instance property on the singleton.{    SiteStructure site = SiteStructure.Instance;    OtherFunction(site); // Use singleton as parameter.}

接口继承

在C#中,接口是一种契约,拥有接口的对象必须满足该接口的每个要求。通常,这些要求是有关对象的一个子集。下面是我们如何使用一个带有接口的单子,在这个例子中,它被称为ISiteInterface

/// <summary>/// Stores signatures of various important methods related to the site./// </summary>public interface ISiteInterface{};/// <summary>/// Skeleton of the singleton that inherits the interface./// </summary>class SiteStructure : ISiteInterface{    // Implements all ISiteInterface methods.    // [omitted]}/// <summary>/// Here is an example class where we use a singleton with the interface./// </summary>class TestClass{    /// <summary>    /// Sample.    /// </summary>    public TestClass()    {        // Send singleton object to any function that can take its interface.        SiteStructure site = SiteStructure.Instance;        CustomMethod((ISiteInterface)site);    }    /// <summary>    /// Receives a singleton that adheres to the ISiteInterface interface.    /// </summary>    private void CustomMethod(ISiteInterface interfaceObject)    {        // Use the singleton by its interface.    }}

现在我们可以为任何一个符合接口的对象的实现重用我们的单子。可能有1个,2个,或者10个。我们不需要一遍又一遍地重写任何东西。我们更常规地存储状态,按接口使用对象,并可以使用传统的面向对象编程的最佳实践。重用代码可以更容易地控制对象的状态。这有利于大大改善代码共享和无限清洁的代码体。

结论

有了更少的代码,你的程序往往会有更少的bug,并且更容易维护。与静态类相比,单子模式的其他优点是。

  • 可测试性: 测试单子模式要比静态类容易得多。

  • 内存管理 : 使用单子类可以让你利用管理对象的垃圾收集的优势

  • 依赖性注入 : 你不能对静态类使用构造函数注入,但你可以对单子类使用。

  • 可扩展性: 你可以在单子类中使用扩展方法,但不能在静态类中使用。