静态类和单例模式之间的区别?

Difference between static class and singleton pattern?

静态类和单例模式之间存在什么实际(即实际)差异?

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


是什么让您说单例方法或静态方法不是线程安全的?通常两者都应该实现为线程安全的。

单例方法和一组静态方法之间的最大区别是,单例方法可以实现接口(或者从有用的基类派生,尽管在我的经验中这不太常见),所以您可以像传递"另一个"实现一样传递单例。


真正的答案是乔恩·斯基特,在这里的另一个论坛上。

A singleton allows access to a single
created instance - that instance (or
rather, a reference to that instance)
can be passed as a parameter to other
methods, and treated as a normal
object.

A static class allows only static
methods.


  • 单例对象存储在堆中,而静态对象存储在堆栈中。
  • 我们可以克隆(如果设计器不禁止)singleton对象,但不能克隆静态类对象。.
  • 单例类遵循面向对象原则,静态类不遵循。
  • 我们可以用一个单例类来实现一个interface,但是类的静态方法(例如c static class不能实现。

  • 与静态类相比,单例模式有几个优点。首先,单例可以扩展类和实现接口,而静态类不能(它可以扩展类,但不继承它们的实例成员)。单例可以延迟或异步初始化,而静态类通常在首次加载时进行初始化,从而导致潜在的类装入器问题。然而,最重要的优点是,单例可以被多态处理,而不必强迫用户假设只有一个实例。


    static类不适用于任何需要状态的东西。它对于将一系列功能放在一起很有用,即在项目中使用Math(或Utils)。所以类名只是给了我们一个线索,在哪里我们可以找到函数,什么都没有。

    Singleton是我最喜欢的模式,我使用它来在一个点上管理一些东西。它比static类更灵活,可以保持它的状态。它可以实现接口,从其他类继承并允许继承。

    我在staticSingleton之间选择的规则:

    如果有一系列的函数应该放在一起,那么选择static。任何其他需要单一访问某些资源的东西都可以作为Singleton来实现。


    静态类:

  • 无法创建静态类的实例。

  • 当加载包含类的程序或命名空间时,由.NET框架公共语言运行库(CLR)自动加载。

  • 静态类不能有构造函数。

  • 我们不能将静态类传递给方法。

  • 我们不能将静态类继承到C中的另一个静态类。

  • 具有所有静态方法的类。

  • 更好的性能(静态方法在编译时绑定)

  • Singleton:

  • 您可以创建对象的一个实例并重用它。

  • 当用户请求时,第一次创建singleton实例。

  • singleton类不能有构造函数。

  • 可以创建singleton类的对象并将其传递给方法。

  • 单例类不表示继承的任何限制。

  • 我们可以处理单例类的对象,但不能处理静态类的对象。

  • 方法可以被重写。

  • 可以在需要时延迟加载(总是加载静态类)。

  • 我们可以实现接口(静态类不能实现接口)。


  • 静态类是只有静态方法的类,对于静态方法,更好的词是"函数"。静态类中包含的设计样式是纯过程的。

    另一方面,singleton是面向对象设计的特定模式。它是一个对象的实例(具有该对象固有的所有可能性,例如多态性),具有一个创建过程,以确保在该特定角色的整个生命周期中只有一个实例。


    在singleton模式中,可以将singleton创建为派生类型的实例,但不能用静态类来实现。

    快速实例:

    1
    2
    3
    4
    if( useD3D )
        IRenderer::instance = new D3DRenderer
    else
        IRenderer::instance = new OpenGLRenderer


    扩大乔恩·斯基特的答案

    The big difference between a singleton and a bunch of static methods is that singletons can implement interfaces (or derive from useful base classes, although that's less common IME), so you can pass around the singleton as if it were"just another" implementation.

    在单元测试类时,单例更容易使用。无论您将singleton作为参数(构造器、setter或方法)传递到哪里,您都可以替代singleton的模拟或存根版本。


    单例的另一个优点是它可以很容易地序列化,如果需要将其状态保存到光盘上,或者将其远程发送到某个地方,则可能需要序列化。


    这是一篇好文章:http://javarevisited.blogspot.com.au/2013/03/difference-between-singleton-pattern-vs-static-class-java.html

    静态类

    • 具有所有静态方法的类。
    • 更好的性能(静态方法在编译时绑定)
    • 无法重写方法,但可以使用方法隐藏。(Java中隐藏的方法是什么?)甚至javadoc的解释也令人困惑)

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      public class Animal {
          public static void foo() {
              System.out.println("Animal");
          }
      }

      public class Cat extends Animal {
          public static void foo() {  // hides Animal.foo()
              System.out.println("Cat");
          }
      }

    独生子女

    • 只能实例化一次的对象。
    • 方法可以被重写(为什么Java不允许重写静态方法?)
    • 比静态方法更容易模拟
    • 更好地保持状态

    总之,我将只使用静态类来保存Util方法,并将singleton用于其他所有方法。

    编辑

    • 静态类也是懒惰加载的。谢谢你(静态类初始化何时发生?)

    • 静态类的方法隐藏。谢谢@maxpeng。


    我不是一个伟大的OO理论家,但据我所知,我认为静态类与单例类相比唯一缺少的OO特性是多态性。但是如果您不需要它,对于静态类,您当然可以拥有继承(不确定接口实现)以及数据和函数封装。

    Morendil的评论,"静态类中体现的设计风格纯粹是程序性的",我可能是错的,但我不同意。在静态方法中,您可以访问静态成员,这与访问其单个实例成员的单实例方法完全相同。

    编辑:我现在想的另一个区别是静态类在程序启动*时被实例化,并且在程序的整个生命周期中都存在,而单个类在某个点上被显式实例化,并且也可以被销毁。

    *或者它可以在第一次使用时被实例化,这取决于语言,我想。


    为了说明jon的观点,如果logger是一个静态类,下面所示的操作将无法完成。类SomeClass期望将ILogger实现的一个实例传递到其构造函数中。

    单例类对于实现依赖项注入很重要。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;

    namespace ConsoleApplication2
    {
        class Program
        {
            static void Main(string[] args)
            {

                var someClass = new SomeClass(Logger.GetLogger());
            }


        }

        public class SomeClass
        {
            public SomeClass(ILogger MyLogger)
            {

            }
        }

        public class Logger : ILogger
        {
            private static Logger _logger;
            private Logger() { }

            public static Logger GetLogger()
            {
                if (_logger==null)
                {
                    _logger = new Logger();
                }

                return _logger;
            }

            public void Log()
            {

            }

        }


        public interface ILogger
        {
             void Log();
        }
    }

    单例类只是一个普通的类,它被实例化,但仅仅是从客户机代码中间接地实例化一次。静态类未实例化。据我所知,静态方法(静态类必须有静态方法)比非静态方法更快。

    编辑:fxcop性能规则描述:"不访问实例数据或调用实例方法的方法可以标记为静态(在VB中共享)。这样做之后,编译器将向这些成员发出非虚拟调用站点,这将阻止在运行时检查确保当前对象指针非空的每个调用。这可以为性能敏感的代码带来可测量的性能增益。在某些情况下,访问当前对象实例失败表示存在正确性问题。"我不知道这是否也适用于静态类中的静态方法。


    singleton是被实例化的,它只是有一个实例被实例化过,因此singleton中的singleton是被实例化过的。

    静态类不能由它本身以外的任何东西实例化。


    从测试的角度来看,单例是更好的方法。与静态类不同,singleton可以实现接口,您可以使用模拟实例并注入它们。

    在下面的示例中,我将说明这一点。假设您有一个方法isgoodprice(),它使用一个方法getprice(),并且您将getprice()实现为单例中的一个方法。

    提供getPrice功能的singleton:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    public class SupportedVersionSingelton {

        private static ICalculator instance = null;

        private SupportedVersionSingelton(){

        }

        public static ICalculator getInstance(){
            if(instance == null){
                instance = new SupportedVersionSingelton();
            }

            return instance;
        }

        @Override
        public int getPrice() {
            // calculate price logic here
            return 0;
        }
    }

    getprice的使用:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class Advisor {

        public boolean isGoodDeal(){

            boolean isGoodDeal = false;
            ICalculator supportedVersion = SupportedVersionSingelton.getInstance();
            int price = supportedVersion.getPrice();

            // logic to determine if price is a good deal.
            if(price < 5){
                isGoodDeal = true;
            }

            return isGoodDeal;
        }
    }


    In case you would like to test the method isGoodPrice , with mocking the getPrice() method you could do it by:
    Make your singleton implement an interface and inject it.



      public interface ICalculator {
            int getPrice();
        }

    最终单例实施:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    public class SupportedVersionSingelton implements ICalculator {

        private static ICalculator instance = null;

        private SupportedVersionSingelton(){

        }

        public static ICalculator getInstance(){
            if(instance == null){
                instance = new SupportedVersionSingelton();
            }

            return instance;
        }

        @Override
        public int getPrice() {
            return 0;
        }

        // for testing purpose
        public static void setInstance(ICalculator mockObject){
            if(instance != null ){
    instance = mockObject;
        }

    测试类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public class TestCalculation {

        class SupportedVersionDouble implements ICalculator{
            @Override
            public int getPrice() {
                return 1;
            }  
        }
        @Before
        public void setUp() throws Exception {
            ICalculator supportedVersionDouble = new SupportedVersionDouble();
            SupportedVersionSingelton.setInstance(supportedVersionDouble);

        }

        @Test
        public void test() {
              Advisor advidor = new Advisor();
              boolean isGoodDeal = advidor.isGoodDeal();
              Assert.assertEquals(isGoodDeal, true);

        }

    }

    如果我们选择使用静态方法来实现getPrice(),那么模拟getPrice()就很困难了。您可以用电源模拟静态,但并非所有产品都可以使用它。


    我同意这个定义:

    The word"single" means single object across the application life
    cycle, so the scope is at application level.

    The static does not have
    any Object pointer, so the scope is at App Domain level.

    Moreover both should be implemented to be thread-safe.

    您可以发现关于:单例模式和静态类的有趣的其他差异


    主要区别在于:

    • singleton有一个实例/对象,而static类是一组静态方法
    • 单例可以扩展,例如通过静态接口上课不能。
    • 可以继承singleton,它支持另一方面,静态类不能被继承我们需要改变自己。
    • 可以将singleton对象作为静态类传递给方法。没有实例不能作为参数传递

    一个显著的区别是单例的不同实例化。

    对于静态类,它是由clr创建的,我们无法控制它。使用singleton,对象将在尝试访问的第一个实例上实例化。


    我们的数据库框架可以连接到后端,为了避免多个用户的脏读,我们使用了单实例模式来确保在任何时候都有单个实例可用。

    在C中,静态类不能实现接口。当一个实例类需要实现一个用于业务契约或IOC目的的接口时,这就是我使用不带静态类的单例模式的地方。

    singleton提供了一种在无状态场景中维护状态的方法

    希望能帮到你……


    在许多情况下,这两个实例没有实际的区别,特别是如果单例实例从未发生过非常缓慢的更改或更改,例如保持配置。

    我认为最大的区别是单体仍然是一个普通的Java bean,而不是一个专门的静态Java类。因此,在更多的情况下,单例被接受;事实上,它是默认的Spring框架的实例化策略。消费者可能知道,也可能不知道这是一个被传递的单子,它只是把它当作一个普通的JavaBean。如果需求发生了变化,而单例需要成为原型,正如我们在春天经常看到的那样,它可以完全无缝地完成,而无需对消费者进行代码行更改。

    前面有人提到静态类应该是纯过程的,例如java.lang.math。在我看来,这样的类不应该被传递,它们不应该将静态final作为属性来保存。对于其他的一切,使用一个单件,因为它更灵活,更容易维护。


  • 延迟加载
  • 支持接口,以便提供单独的实现
  • 返回派生类型的能力(作为Lazyloading和接口实现的组合)

  • 我们可以创建singleton类的对象并将其传递给方法。

  • singleton类对继承没有任何限制。

  • 我们不能释放静态类的对象,但可以释放单例类。


  • 我阅读了以下内容,认为这也很有意义:

    Taking Care of Business

    Remember, one of the most important OO rules is that an object is responsible for itself. This means that issues regarding the life cycle of a class should be handled in the class, not delegated to language constructs like static, and so on.

    从《面向对象的思维过程》第4版开始。


    从客户机的角度来看,静态行为对于客户机来说是已知的,但是单例行为可以在客户机隐藏的情况下完成。客户机可能永远不会知道只有一个实例在他周围一次又一次地玩。


    在我写的一篇文章中,我描述了我的观点,即为什么单例类比静态类要好得多:

  • 静态类实际上不是规范类——它是一个包含函数和变量的命名空间
  • 由于违反了面向对象的编程原则,使用静态类不是一个好的实践
  • 静态类不能作为其他类的参数传递
  • 静态类不适用于"惰性"初始化
  • 静态类的初始化和使用总是很难跟踪的
  • 实现线程管理很困难

  • a.序列化-静态成员属于类,因此无法序列化。

    虽然我们已经将构造函数设置为私有的,但是静态成员变量仍然会被携带到子类中。

    我们不能进行懒惰的初始化,因为所有的东西都将只在类加载时加载。


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

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


    Java中的静态类只有静态方法。它是一个集装箱功能。它是基于过程编程设计创建的。

    单例类是面向对象设计中的一种模式。独生子女类在JVM中只有一个对象实例。这种模式是以这样一种方式实现,即始终只有一个JVM中存在的类。


    正如我理解静态类和非静态单例类之间的区别一样,静态类只是C中一个未实例化的"类型",其中单例是一个真正的"对象"。换句话说,静态类中的所有静态成员都被分配给该类型,但是在单例中,这些静态成员被封装在对象下。但请记住,静态类的行为仍然像引用类型一样,因为它不是像结构那样的值类型。

    这意味着当您创建一个singleton时,由于类本身不是静态的,但它的成员是静态的,所以它的优点是在singleton中引用自身的静态成员连接到实际的"对象",而不是一个空的"类型"。除了它的其他特性和内存使用之外,这种方式澄清了静态单例和非静态单例之间的区别,这让我很困惑。

    两者都使用静态成员,静态成员是成员的单一副本,但单例将引用的成员包装在一个真正的实例化"对象"周围,该对象的地址除了静态成员之外还存在。该对象本身具有属性,其中in可以传递和引用,并添加值。静态类只是一个类型,因此它不存在,只指向其静态成员。这个概念在继承和其他问题之外巩固了单例类和静态类的目的。


    我头脑中的不同是实现面向对象编程(单例/原型)或函数编程(静态)。

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

    另一方面,使用静态来实现函数编程。静态成员属于类。它们是无状态的。

    顺便问一下,您是否知道可以创建单例静态类:)


    当我希望类具有完整的功能时,例如有许多方法和变量,我使用singleton;

    如果我希望类中只有一个或两个方法,例如mailservice类,它只有一个方法sendmail(),那么我使用静态类和方法。


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


    Both can be invoked without instantiation, both provide only one"Instance" and neither of them is thread-safe. Is there any other difference?

    这个问题是错误的,两种说法都是错误的。请注意:这里的静态类是指嵌套的静态类,而不是只包含静态方法的类。

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

    让我更正一下这些陈述:

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

  • 没有一个类本质上是线程安全的,它必须通过编程实现线程安全。它既可以用于嵌套静态类,也可以用于单例类。

  • 下面还有一些反神话的方法(这个问题的大多数答案都给出了这些说法,所以认为用程序证明它是好的):

  • 嵌套静态类可以像任何其他类一样实现接口。
  • 嵌套静态类可以扩展其他非最终类。
  • 嵌套的静态类不能有实例变量。
  • 嵌套静态类不能具有参数化构造函数。
  • 在下面的代码中,您可以看到嵌套的静态类NestedStaticClass实现接口、扩展另一个类、具有实例变量和参数化构造函数。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    100
    101
    102
    103
    104
    105
    106
    107
    108
    109
     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;
            }

        }


    我会努力超越WTMI和WTL;博士回答。

    单件是一个对象的实例…完全停止

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

    singleton的类通常采取步骤来确保构建一个实例;这很聪明,但不是必需的。

    示例:var connection=connection.instance;

    假设这是连接类:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    public sealed class Connection
    {
        static readonly Connection _instance = new Connection();

        private Connection()
        {
        }

        public static Connection Instance
        {
            get
            {
               return _instance;
            }
        }
    }

    请注意,您可以在该类上抛出一个接口,并出于测试目的对其进行模拟,这对于静态类是不容易做到的。