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

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

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

617850 次浏览

Singleton是实例化的。只是只创建了一个实例,因此Singleton中的单一

另一方面,静态类不能被实例化。

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

快速示例:

if( useD3D )IRenderer::instance = new D3DRendererelseIRenderer::instance = new OpenGLRenderer

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

单例和一堆静态方法之间的最大区别在于单例可以实现接口(或从有用的基类派生,尽管根据我的经验,这不太常见),因此您可以传递单例,就好像它是“只是另一个”实现一样。

真正的答案是Jon Skeet,在另一个论坛上

单例允许访问单个创建的实例-该实例(或更确切地说,是对该实例的引用)可以作为参数传递给其他方法,并视为正常对象。

静态类只允许静态方法。

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

静态类是一个只有静态方法的类,更好的词是“函数”。静态类所体现的设计风格纯粹是过程性的。

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

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

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

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

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

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

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

static类不适用于任何需要状态的东西。它对于将一堆函数放在一起很有用,即Math(或项目中的Utils)。所以类名只是给了我们一个线索,我们可以在哪里找到函数,仅此而已。

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

staticsingleton之间进行选择的规则:

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

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

  1. 延迟加载
  2. 支持接口,以便可以提供单独的实现
  3. 能够返回派生类型(作为lazyload和接口实现的组合)

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

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

在许多情况下,这两者没有实际区别,特别是如果单例实例从不更改或更改非常缓慢(例如保持配置)。

我想说最大的区别是单例仍然是一个正常的JavaBean,与专门的仅静态Java类相反。正因为如此,单例在更多的情况下被接受;它实际上是Spring Framework的默认实例化策略。消费者可能知道也可能不知道这是一个传递的单例,它只是像普通的Javabean一样对待它。如果需求变化,单例需要成为原型,正如我们在Spring中经常看到的那样,它可以完全无缝地完成,而无需向消费者更改一行代码。

前面有人提到静态类应该是纯过程的,比如java.lang.Math。在我看来,这样的类永远不应该被传递,它们永远不应该持有静态Final以外的任何东西作为属性。对于其他所有东西,使用单例,因为它更灵活,更容易维护。

为了避免跨多个用户的脏读,我们使用单例模式来确保我们在任何时间点都有单个实例可用。

在c#中,静态类不能实现接口。当单个实例类需要实现用于业务合同或IoC目的的接口时,这就是我在没有静态类的情况下使用Singleton模式的地方

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

希望对你有帮助…

一个显著的区别是Singleton附带的不同实例化。

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

  1. 单例对象存储在中,但静态对象存储在堆栈中。
  2. 我们可以克隆(如果设计者不允许)单例对象,但我们不能克隆静态类对象.
  3. 单例类遵循OOP(面向对象原则),静态类不遵循。
  4. 我们可以用Singleton类实现interface,但类的静态方法(或例如C#static class)不能。

扩展到Jon Skeet的回答

单例和一堆静态方法之间的最大区别在于单例可以实现接口(或从有用的基类派生,尽管这在IME中不太常见),因此您可以将单例作为“只是另一个”实现来传递。

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

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

为了说明Jon的观点,如果Logger是一个静态类,则无法完成下面所示的工作。

单例类对于依赖注入是很重要的。

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();}}

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

  1. 静态类实际上不是规范类-它是一个包含函数和变量的命名空间
  2. 使用静态类不是一个好的做法,因为它破坏了面向对象的编程原则
  3. 静态类不能作为其他类的参数传递
  4. 静态类不适合“懒惰”初始化
  5. 静态类的初始化和使用总是很难跟踪
  6. 实现线程管理很难

序列化-静态成员属于类,因此不能序列化。

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

c.我们不能进行延迟初始化,因为所有内容都将在类加载时加载。

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

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

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

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

单例提供getPrice功能:

public class SupportedVersionSingelton {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){if(instance == null){instance = new SupportedVersionSingelton();}
return instance;}
@Overridepublic int getPrice() {// calculate price logic herereturn 0;}}

使用getPrice:

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();}

最终Singleton实现:

public class SupportedVersionSingelton implements ICalculator {
private static ICalculator instance = null;
private SupportedVersionSingelton(){
}
public static ICalculator getInstance(){if(instance == null){instance = new SupportedVersionSingelton();}
return instance;}
@Overridepublic int getPrice() {return 0;}
// for testing purposepublic static void setInstance(ICalculator mockObject){if(instance != null ){instance = mockObject;}

测试类:

public class TestCalculation {
class SupportedVersionDouble implements ICalculator{@Overridepublic int getPrice() {return 1;}}@Beforepublic void setUp() throws Exception {ICalculator supportedVersionDouble = new SupportedVersionDouble();SupportedVersionSingelton.setInstance(supportedVersionDouble);
}
@Testpublic void test() {Advisor advidor = new Advisor();boolean isGoodDeal = advidor.isGoodDeal();Assert.assertEquals(isGoodDeal, true);
}
}

如果我们选择使用静态方法来实现getPrice(),则很难模拟getPrice()。你可以用电源模拟来模拟静态,但不是所有的产品都可以使用它。

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

静态类

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

    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");}}

Singleton

In summary, I would only use static classes for holding util methods, and using Singleton for everything else.


Edits

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

静态类:-

  1. 您无法创建静态类的实例。

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

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

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

  5. 具有所有静态方法的类。

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

单例:-

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

  2. Singleton实例是在用户请求时首次创建的。

  3. 您可以创建单例类的对象并将其传递给方法。

  4. Singleton类没有说明继承的任何限制。

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

  6. 方法可以被覆盖。

  7. 需要时可以延迟加载(静态类总是加载的)。

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

我读了下面的内容,也觉得很有道理:

照顾生意

请记住,最重要的OO规则之一是对象对自己负责。这意味着有关类生命周期的问题应该在类中处理,而不是委托给静态等语言结构。

从书面向对象的思维过程第四版。

我同意这个定义:

单词“单一”表示整个应用程序生命周期中的单个对象循环,所以范围在应用程序级别。

静态没有任何对象指针,因此范围在App Domain级别。

此外,两者都应该实现为线程安全。

您可以找到有趣的其他差异:单例模式与静态类

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

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

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

让我纠正一下这些说法:

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

  2. 没有一个类是天生线程安全的,它必须以编程方式使其线程安全。嵌套静态类和单例都可以做到这一点。

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

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

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

 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 constructorpublic 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; DR响应。

Singletons是一个对象的实例…句号

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

单例类通常会采取措施来确保构建一个实例;这很聪明,但不是必需的。

示例:var连接=Connection. Instance;

假设这是Connection类:

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

请注意,您可以在该类上抛出一个接口并对其进行模拟以进行测试,这是静态类无法轻松完成的事情。

  1. 我们可以创建单例类的对象并将其传递给方法。

  2. 单例类没有任何继承限制。

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

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

这意味着当你创建一个Singleton时,因为类本身不是静态的,但它的成员是静态的,优点是Singleton中引用自身的静态成员连接到一个实际的“对象”而不是自身的空心“类型”。这种澄清现在澄清了静态和非静态单例之间的区别,超出了它的其他特性和内存使用,这对我来说很困惑。

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

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

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

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

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

主要区别是:

  • Singleton有一个实例/对象,而静态类是一堆静态方法
  • Singleton可以在静态时通过接口进行扩展类不能。
  • 可以继承Singleton,它支持SOLID原则另一方面静态类不能被继承我们需要自己做出改变。
  • 单例对象可以传递给方法,而静态类作为它没有实例不能作为参数传递

Java中的A静态类只有静态方法函数。它是基于过程编程设计创建的。

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

带有静态类的示例

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 ");}}}

与静态类的区别

JDK有单例和静态的例子,一方面java.lang.Math是带有静态方法的最终类,另一方面java.lang.Runtime是单例类。

单例的优点

  • 如果需要维护状态,比单例模式是比静态类更好的选择,因为在静态类中维护状态会导致bug,特别是在并发环境中,这可能导致竞争条件,而不需要通过多个线程进行足够的同步并行修改。

  • 单例类如果是一个重对象,可以延迟加载,但静态类没有这样的优势,总是急切地加载。

  • 使用单例,您可以使用继承和多态来扩展基类、实现接口并提供不同的实现。

  • 由于Java中的静态方法不能被覆盖,它们会导致不灵活。另一方面,您可以通过扩展来覆盖单例类中定义的方法。

静态类的缺点

  • 为单例编写单元测试比静态类更容易,因为您可以在期望单例时传递模拟对象。

静态类的优点

  • 静态类比单例提供更好的性能,因为静态方法在编译时绑定。

单例模式有几种实现方式,每一种都有优点和缺点。

  • 急切加载单例
  • 双重检查锁定单例
  • 按需初始化持有者习惯用法
  • 基于枚举的单例

详细描述他们每个人都太冗长,所以我只是把一个链接到一个好的文章-关于Singleton你想知道的一切

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

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

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

除非你想要一个没有任何实例的整个应用程序-都是静态的!-那么单例对于这些情况是有意义的,我们不能依赖缺乏人为错误作为唯一保证某些东西不会被覆盖。

但要注意,单例不能保证状态无处不在。您的网络处理程序本身也可能依赖于其他单例,等等。现在我们有状态生活在许多单例中……太棒了。

而且没有编译器可以确保单例是编译时所有状态或任何其他类似想法的所在。你可以在一个有单例的类上有一百个静态变量。单例可以访问静态变量。编译器不会关心。

所以我要提醒任何人不要假设使用单例可以保证任何关于状态所在位置的事情。

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

在像Swift这样的语言中,Singleton根本不是必需的,可以获得依赖注入、可测试代码、管理良好的状态、线程安全访问器、多态等。

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

  • Singleton类在应用程序生命周期内提供一个对象(只有一个实例),例如java.lang.Runtime

    虽然静态类只提供java.lang.Math等静态方法

  • Java中的静态方法不能被覆盖,但可以通过扩展它来覆盖Singleton类中定义的方法。

  • 单例类能够继承和多态性来扩展基类,实现接口并能够提供不同的实现。而静态不是。

例如:java.lang.Runtime是Java中的单例类,调用getRuntime()方法返回与当前Java应用程序关联的运行时对象,但确保每个JVM只有一个实例。

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

以下是静态类和单例之间的一些主要区别:

1.单例是一种模式,而不是像静态那样的关键字。因此,创建静态类的静态关键字就足够了,而在单例的情况下,需要为单例编写逻辑。

2.单例类必须有私有的默认实例构造函数,而静态类不能包含任何实例构造函数。

3.静态类既不实例化也不扩展,而单例类可以。

4.静态类是隐式密封的,但单例类必须装饰为显式密封。

5.单例可以实现接口或从另一个类继承,但静态类既不实现接口,也不从任何其他类扩展。

6.我们不能用静态类实现依赖注入,但是DI可以用单例类实现,因为它可以是接口驱动的。静态类的作用域位于应用程序域级别,因为它由CLR管理,而单例对象的作用域跨越应用程序生命周期。

7.静态类不能有任何析构函数,但单例类可以定义析构函数。

8.单例类实例可以作为参数传递给另一个方法,而静态类不能,因为它只包含静态成员。