【问题标题】:Difference between static class and singleton pattern?静态类和单例模式之间的区别?
【发布时间】:2010-10-05 21:26:00
【问题描述】:

静态类和单例模式之间存在什么真正的(即实际的)区别?

两者都可以在没有实例化的情况下调用,都只提供一个“实例”,而且它们都不是线程安全的。还有其他区别吗?

【问题讨论】:

标签: design-patterns static singleton


【解决方案1】:

单个静态类实例(即类的单个实例,恰好是静态或全局变量)和单个静态指针之间存在巨大差异 到堆上的类的一个实例:

当您的应用程序退出时,将调用静态类实例的析构函数。这意味着如果您将该静态实例用作单例,您的单例将停止正常工作。如果仍有使用该单例的代码在运行,例如在不同的线程中,则该代码可能会崩溃。

【讨论】:

  • 那么如果应用程序退出,Singleton 还会保留在内存中吗?
  • 我想你的意思是当你当前的线程退出时,而不是应用程序,对吧?如果应用程序退出,其他线程将无法使用其中的任何内容。
【解决方案2】:

我脑子里的区别是实现面向对象编程(单例/原型)或函数式编程(静态)。

我们过于关注单例模式创建的对象的数量,而我们应该关注的是最终我们持有一个对象。就像其他人已经说过的那样,它可以扩展,作为参数传递,但最重要的是它是全状态的。

另一方面,静态用于实现函数式编程。静态成员属于一个类。他们是无国籍的。

顺便说一句,您知道您可以创建单例静态类 :)

【讨论】:

  • 将单例作为参数传递有什么意义,因为它总是在类上具有静态引用?
【解决方案3】:

当我想要具有完整功能的课程时,例如方法和变量很多,我用的是单例的;

如果我想要一个只有一两个方法的类,例如MailService 类,它只有 1 个方法 SendMail() 我使用静态类和方法。

【讨论】:

    【解决方案4】:

    据我了解静态类和非静态单例类之间的区别,静态只是 C# 中的非实例化“类型”,其中单例是真正的“对象”。换句话说,静态类中的所有静态成员都分配给该类型,但在 Singleton 中却位于对象之下。但请记住,静态类的行为仍然像引用类型,而不是像 Struct 这样的值类型。

    这意味着当你创建一个单例时,因为类本身不是静态的,但它的成员是,优点是单例中引用自身的静态成员连接到一个实际的“对象”而不是空心的“类型”本身。现在,除了其他功能和内存使用情况之外,这种方式澄清了静态和非静态单例之间的区别,这让我感到困惑。

    两者都使用作为成员的单个副本的静态成员,但单例将引用的成员包装在一个真正的实例化“对象”周围,该对象的地址除了其静态成员之外还存在。该对象本身具有可以传递和引用的属性,从而增加了价值。 Static 类只是一种类型,因此除了指向其静态成员之外它不存在。这个概念在某种程度上巩固了单例与静态类的目的,超越了继承和其他问题。

    【讨论】:

      【解决方案5】:

      单例只不过是类上的一次写入静态变量,一旦初始化,它总是引用自身的同一个实例。

      因此,您不能“使用单例代替静态变量”,也不能通过使用单例来避免在静态变量中保持状态。

      单例的优点仅在于:它不会被重新初始化即使其他代码尝试重新初始化它一千次。这对于像网络处理程序这样的东西来说非常有用,你知道,如果一个实例在等待响应的过程中被另一个实例替换,它会很糟糕。

      除非您想要一个在任何地方都没有实例的整个应用程序——全是静态的!——那么单例对于我们不能依靠缺乏人为错误作为唯一保证不会被覆盖的情况是有意义的。

      但请注意,单身并不能保证在任何地方都存在状态。您的网络处理程序本身也可能依赖于其他单例等。现在我们有状态生活在许多单例中......太棒了。

      并且没有编译器可以确保在编译时单例是您所有状态或任何其他此类想法所在的位置。您可以在具有单例的类上拥有一百个静态变量。并且单例可以访问静态变量。并且编译器不会在意。

      所以我会提醒任何人不要假设使用单例可以保证任何关于状态所在的位置。 它唯一的保证就是它永远是它的类的唯一实例。这也是它唯一的优势。

      其他答案声称单例的任何其他优势都是编译器不保证的,并且可能因语言而异。依赖注入是一种可能依赖于单例的补充模式,尽管它可能是也可能不是给定语言中的最佳解决方案或唯一解决方案。在缺乏泛型或对调用静态访问器和函数施加任意限制的语言中,诉诸单例模式确实可能是解决给定问题的最佳可用解决方案。

      在像 Swift 这样的语言中,Singleton 根本不需要获得依赖注入、可测试的代码、良好管理的状态、线程安全的访问器、多态性等。但是它对于保证单个实例仍然有用。

      回顾一下:单例只不过是一个静态变量,它可以防止存在给定类的多个实例,以及防止单个实例被新实例覆盖。就是这样,句号,句号。

      【讨论】:

        【解决方案6】:

        静态类示例

        public class Any {
        
            private static Any instance = new Any();
        
            private Singleton() {
                System.out.println("creating");
            }
        }
        

        单例模式只存在一个实例:

        public class Singleton {
        
            private static Singleton instance = new Singleton();
        
            private Singleton() {
                System.out.println("creating");
                if (instance != null) {
                    throw new RuntimeException("Imposible create a new instance ");
                }
            }
        }
        

        【讨论】:

        • 上面的例子不是静态类。
        • 如果你实例化它,那么拥有一个单例有什么意义?
        【解决方案7】:

        静态类通常用于库,如果我只需要特定类的一个实例,则使用单例。 但从内存的角度来看,还是有一些区别:通常在堆中只分配对象,分配的唯一方法是当前正在运行的方法。静态类的所有方法也都是静态的,并且从一开始就在堆中,因此通常静态类会消耗更多内存。

        【讨论】:

          【解决方案8】:

          Singleton 的一个主要优势:多态性 例如:使用类工厂创建实例(根据一些配置说),我们希望这个对象是真正的单例。

          【讨论】:

            【解决方案9】:

            两者都可以在没有实例化的情况下调用,都只提供一个“实例”,而且它们都不是线程安全的。还有其他区别吗?

            这个问题是错误的,它的陈述都是错误的。 请注意:这里的静态类是指嵌套的静态类,而不是只有静态方法的类。

            我假设(即静态类意味着嵌套的静态类,而不是只有静态成员的类)所以因为如果我看到最流行的单例实现,即 DCL 方式,它只不过是实例的静态声明和静态方法获取单例实例。它的一种实现。所以在这种情况下,单例和只有静态成员的类有什么区别。尽管使用 Enum 也可以实现类似的其他实现。

            让我更正这些陈述:

            1. 单例类可以在应用程序范围内具有单实例。嵌套的静态类可以有多个实例(参见下面的代码作为证明)。阅读嵌套类的基础知识here

            2. 没有一个类本质上是线程安全的,它必须以编程方式使其成为线程安全的。嵌套静态类和单例都可以。

            下面还有一些神话破坏者(这个问题的大多数答案都给出了这些陈述,所以认为以编程方式证明它会很好):

            1. 嵌套的静态类可以像任何其他类一样实现接口。
            2. 嵌套的静态类可以扩展其他非最终类。
            3. 嵌套的静态类可以有实例变量。
            4. 嵌套的静态类可以有参数化的构造函数。

            在下面的代码中你可以看到嵌套的静态类NestedStaticClass实现了接口,扩展了另一个类,有实例变量和参数化的构造函数。

             package com.demo.core;
            
                public class NestedStaticClassTest
                {
                    public static void main(String[] args)
                    {
                        OuterClass.NestedStaticClass obj1 = new OuterClass.NestedStaticClass();
                        OuterClass.NestedStaticClass obj2 = new OuterClass.NestedStaticClass();
            
                        if(obj1 == obj2)
                        {
                            System.out.println("Both nested static objects are equal....");
                        }
                        else
                        {
                            System.out.println("NOT EQUAL......");
                        }
            
                        System.out.println(OuterClass.NestedStaticClass.d);
            
                        obj1.setD(5);
            
                        System.out.println(OuterClass.NestedStaticClass.d);
            
                        System.out.println(obj1.sum());
                    }
                }
            
                class OuterClass
                {
                    int a =1;
                    static int b = 2;
            
                    static class NestedStaticClass extends OneClass implements Sample
                    {
                        int c = 3;
                        static int d = 4;
            
                        public NestedStaticClass()
                        {
                        }
            
                        //Parameterized constructor
                        public NestedStaticClass(int z)
                        {
                            c = z;
                        }
            
                        public int sum()
                        {
                            int sum = 0;
                            sum = b + c + d + getE();
                            return sum;
                        }
            
                        public static int staticSum()
                        {
                            int sum = 0;
                            sum = b + d;
                            return sum;
                        }
            
                        public int getC()
                        {
                            return c;
                        }
                        public void setC(int c)
                        {
                            this.c = c;
                        }
                        public static int getD()
                        {
                            return d;
                        }
                        public static void setD(int d)
                        {
                            NestedStaticClass.d = d;
                        }
                    }
                }
            
                interface Sample
                {
            
                }
            
                class OneClass
                {
                    int e = 10;
                    static int f = 11;
            
                    public int getE()
                    {
                        return e;
                    }
                    public void setE(int e)
                    {
                        this.e = e;
                    }
                    public static int getF()
                    {
                        return f;
                    }
                    public static void setF(int f)
                    {
                        OneClass.f = f;
                    }
            
                }
            

            【讨论】:

            • 谁说这与 Java 的“嵌套静态类”有关?问题是关于单例与静态设计模式的,根本没有提到 Java。 Java 不像许多其他语言那样具有内置的纯静态类概念,但即使在 Java 专家the phrase "static class" means "a class, having all static methods" 中也是如此。
            • @StriplingWarrior:我假设是这样(即静态类意味着嵌套静态类而不是只有静态成员的类)因为如果我看到最流行的单例实现,即 DCL 方式,它只不过是静态声明实例和静态方法来获取 Singleton 实例。它的一种实现。所以在这种情况下,单例和只有静态成员的类有什么区别。尽管使用 Enum 也可以实现其他实现。
            • 我并没有真正遵循你的逻辑。单例模式(无论实现如何)意味着只有一个(并且只有一个)实例。这不会改变静态类的定义,也不意味着使用 Java。此外,问使用 Singleton 和 Java 的嵌套静态类之间有什么区别是没有意义的,因为它们有两个完全不同的目的——就像问 iPhone 和雪佛兰之间的区别一样。
            • 是的,单例意味着应用程序中的单个实例。所以你的意思是说不能为只有静态成员的类创建多个实例?
            • 我的意思是,如果你有一个只有静态成员的类,你永远不会实例化它(而单例管理它自己的实例,所以消费代码永远不会直接实例化它)。因此,如果您正在考虑使用单例模式,您可能想知道为什么需要有一个实例:如果您只是将您的状态存储在类的静态字段中,并且您的所有方法都是静态的,那么就没有理由甚至有一个类的实例,对吗?这就是这个问题的本质:这两种模式之间的实际区别是什么?
            【解决方案10】:

            我将尝试超越 WTMI 和 WTL;DR 响应。

            单例是对象的一个​​实例...句号

            您的问题基本上是在询问一个类与该类的实例之间的区别。我认为这很清楚,不需要详细说明。

            单例类一般会采取措施保证一个实例的构造;这很聪明,但不是必需的。

            示例:var connection = Connection.Instance;

            假设这是 Connection 类:

            public sealed class Connection 
            {
                static readonly Connection _instance = new Connection();
            
                private Connection() 
                {
                }
            
                public static Connection Instance
                {
                    get
                    {
                       return _instance;
                    }
                } 
            }
            

            请注意,您可以在该类上抛出一个接口并对其进行模拟以用于测试目的,而静态类无法轻松做到这一点。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2011-10-06
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2011-04-12
              • 2011-10-03
              • 2011-04-01
              • 1970-01-01
              相关资源
              最近更新 更多