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

Jorge Córdoba 1708 singleton static design-patterns

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

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

Jon Skeet.. 1194

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

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

  • 你能给出一个*本身就是线程安全的东西的例子,除了不可变类型吗? (116认同)
  • @Geek:想象一下,单例实现了一个接口`Foo`,你有一个方法将`Foo`作为参数.通过该设置,调用者可以选择使用单例作为实现 - 或者他们可以使用不同的实现.该方法与单例解耦.将其与类只有静态方法的情况相比较 - 每个想要调用这些方法的代码都与类紧密耦合,因为它需要指定哪个类包含静态方法. (44认同)
  • 好吧,如果你喜欢它,也不是天生线程安全的,你必须让他们是线程安全的,他们两个,所以没有区别在那里. (27认同)
  • 对Skeet:人们说单例不是线程安全意味着单独的线程之间共享*不必要*,而堆栈对象在你需要时共享,这意味着你不必进行不必要的同步. (24认同)
  • @AmirBareket:根据单件设计模式,它不是单例 - 如果类本身允许创建多个实例,那么它不是单身IMO,无论工厂做什么. (10认同)
  • @stom:"静态对象存储在堆栈中"a)没有静态对象; b)*所有*静态字段都在堆上. (3认同)
  • Jon,"内在地",我的意思是从程序员/用户的角度来看.很多系统调用或库类是线程安全的所以我不必担心它...但你是对的,我想不出任何东西 (2认同)
  • @WolfmanDragon:我不确定我是否将其称为不可变类型,但是是的,它变得笨拙。埃里克·利珀特(Eric Lippert)在关于不变性的各种变化方面有出色的文章。 (2认同)
  • @JonSkeet你可以解释你的意思*所以你可以传递单身,好像它只是"另一个"实现*.".你不能对一个有一堆静态方法的类做同样的事情.我发现这个问题本身有点令人困惑,因为问题始于"静态类和Singleton之间的差异",你的答案谈到了"单例和一堆静态方法之间的差异".当然,没有静态类的问题. Java除静态嵌套类外. (2认同)
  • @KyleDelaney:无论如何,我都会惊讶地发现任何*显着的差异. (2认同)

Kezzer.. 453

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

单例允许访问单个创建的实例 - 该实例(或者更确切地说,对该实例的引用)可以作为参数传递给其他方法,并作为普通对象处理.

静态类只允许静态方法.

  • 但是,如果可以通过调用静态getInstance()方法从几乎任何地方访问同一个实例,为什么要将Singleton作为参数传递? (59认同)
  • @HenriqueOrdine所以它可以适应现有的代码并提供一个接口? (20认同)
  • @Goran我最初对你的措辞很困惑.你说"你不能在实例上调用静态方法".我把它读作"如果你有一个实例化对象的引用,你就不能调用它可能有的任何静态方法." 那当然是不对的.再次阅读它几次后,我认为你的意思是"从静态方法内部你无法访问类中的非静态对象"这是正确的.想要澄清那些对这些概念不熟悉的人谁会遇到这个答案并阅读你的评论. (13认同)
  • @HenriqueOrdine他们讲的是静态类,而不是静态方法的类.静态类无法实例化.但是,如果传递包含静态方法的(非静态)类的实例,则无法在实例上调用静态方法. (6认同)
  • 什么是静态类?至少在Java中,没有这样的东西. (3认同)

小智.. 354

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

  • 第二个说法是错误的.我们无法克隆Singleton对象.Singleton实现必须拒绝这一点.如果你真的可以克隆Singleton,那就不是Singleton. (90认同)
  • #1并不重要.#2描述了有缺陷的实现.#3完全没有道理. (64认同)
  • 静态对象如何存储在堆栈中?调用方法时会创建新的堆栈帧,它会存储方法的局部变量,当方法返回时会删除此堆栈帧,并且这些局部变量会丢失.确保堆栈速度快,但不适合存储静态对象. (28认同)
  • 这对Java来说是不正确的:单例和静态都不使用堆栈. (17认同)
  • 我无法理解这一个的赞成数量.1)为什么Singleton必须存储在堆栈中?在C#等托管语言中,Java数据存储在托管堆中,本地方法变量/参数除外.2)如果你可以克隆它,那么它不是一个正确实现的单例.3)Singleton被称为OOP反模式; 即如果可能你应该避免的事情.4)这是唯一正确的事情. (16认同)
  • #1.为什么静态对象总是在堆栈中.我不知道java,但是在c ++中我们说堆栈中的对象时,为成员分配的内存应该驻留在堆栈内存中.默认情况下,所有静态数据成员将根据位置/方式转到数据段和剩余成员它正在实例化.使用'new'将转到堆,global或static将转到堆栈中的数据段和本地对象. (4认同)
  • 所有4个理由都是简单的h .. (3认同)
  • #1堆栈提供更快的检索.在某些情况下,这可能很重要. (2认同)

小智.. 144

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

  • +1表示急切初始化静态类. (12认同)
  • +1为好的,实用的点.Singleton模式通常被过度使用,但有一些情况适合它.另见:http://agiletribe.wordpress.com/2013/10/08/dont-abuse-singleton-pattern/ (8认同)

Xaqron.. 69

static类不应该做任何需要状态的东西,它可以将一堆函数放在一起,即Math(或Utils在项目中).因此,班级名称只是给我们一个线索,我们可以在哪里找到这些函数,仅此而已.

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

我对之间进行选择的规则staticsingleton:

如果有一堆功能应该保持在一起,那么static就是选择.可以实现任何其他需要单独访问某些资源的东西singleton.

  • 为什么静态类不能做任何需要保存状态的东西? (11认同)
  • @Trisped:您既没有精确控制初始化也没有最终确定. (9认同)
  • 你失去了我"Singleton是我最喜欢的模式".单身人士是一个如此尖锐的角落,它应该被视为反模式和模式.类可以具有静态状态,这也是单一访问,如果任何静态状态比单例更"单一访问",因为大多数单例实现都被破坏,即.你可以克隆单例,而静态被定义祝福是唯一的. (5认同)

RajeshVerma.. 61

静态类: -

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

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

  3. 静态类不能有构造函数.

  4. 我们无法将静态类传递给方法.

  5. 我们不能将Static类继承到C#中的另一个Static类.

  6. 具有所有静态方法的类.

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

辛格尔顿: -

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

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

  3. Singleton类可以有构造函数.

  4. 您可以创建singleton类的对象并将其传递给method.

  5. Singleton类没有说继承的任何限制.

  6. 我们可以处理单例类的对象而不是静态类的对象.

  7. 方法可以被覆盖.

  8. 可以在需要时加载延迟(始终加载静态类).

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

  • 静态类确实有构造函数:https://msdn.microsoft.com/en-us/library/k9x6w0hc.aspx (10认同)

Morendil.. 51

静态类是仅具有静态方法的类,对于该类,更好的单词将是"函数".静态类中体现的设计风格纯粹是程序性的.

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

  • 所以你认为.我的想法不同.;)例如,想象一个返回接口的单件工厂.你知道你正在获得一个ISingleton(它永远是同一个),但不一定是哪个实现. (31认同)

Don Neufeld.. 35

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

快速示例:

if( useD3D )
    IRenderer::instance = new D3DRenderer
else
    IRenderer::instance = new OpenGLRenderer

  • 它不是真正的单身模式,看起来更像工厂给我. (39认同)
  • 然后是代理单身:) (12认同)
  • 不是真的,两者之间的根本区别在于,Singleton将"缓存"其单个对象并继续返回(引用)同一个对象.Factory模式将创建新实例. (10认同)
  • 嗯,我知道Singleton作为MonoState的各种各样. (3认同)

Mike Rylande.. 25

扩展Jon Skeet的答案

单例和一组静态方法之间的最大区别在于单例可以实现接口(或者从有用的基类派生,尽管这不常见于IME),因此您可以传递单例,就好像它只是"另一个"实现一样.

单元测试课程时,单身人士更容易使用.无论您将单例作为参数(构造函数,设置器或方法)传递,您都可以替换单例的模拟或存根版本.


JackDev.. 23

这是一篇很好的文章: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");
        }
    }
    

独生子

总之,我只使用静态类来保存util方法,并将Singleton用于其他所有方法.


编辑

  • 我不知道java,但在.Net中,你的最后两点是不正确的.静态类可以引用静态属性和字段,因此在状态上它们是相等的.它们是延迟加载的 - 静态构造函数在以下情况下运行:1)创建类的实例.2)引用该类的任何静态成员.1不适用,留下2.因此,静态类直到第一次使用时才会加载. (4认同)

Alex.. 22

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


Petruza.. 18

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

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

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

*或者它可能会在第一次使用时被实例化,具体取决于语言,我认为.

  • 是的,其他人似乎都忽略了这样一个事实,即具有静态方法的类也可以拥有私有静态字段,它仍然可以用来维护状态(并通过公共静态setter/getter将它们中的一些暴露给客户端代码). (15认同)

developer747.. 17

为了说明Jon的观点,如果Logger是一个静态类,则无法完成下面显示的内容.该类SomeClass需要将ILogger实现的实例传递给它的构造函数.

Singleton类对于依赖注入是很重要的.

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


agnieszka.. 13

单例只是一个正常的类,它被实例化,但只是一次,间接来自客户端代码.静态类未实例化.据我所知,静态方法(静态类必须有静态方法)比非静态方法快.

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


Kezzer.. 11

Singleton是实例化的,只有一个实例被实例化,因此Singleton中的单个实例.

静态类不能由其他任何东西实例化.


Amir Bareket.. 7

从测试的角度看,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;
    }

    @Override
    public int getPrice() {
        // calculate price logic here
        return 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;
    }

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

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

考试类:

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()是很困难的.您可以使用power mock来模拟静态,但并非所有产品都可以使用它.


Alessandro O.. 6

我同意这个定义:

" 单个 " 一词在整个应用程序生命周期中表示单个对象,因此范围在应用程序级别.

没有任何对象的指针,因此范围是在应用程序域级别.

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

您可以找到有趣的其他差异:Singleton Pattern与Static Class


Faran Shabbi.. 6

主要区别是:

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


Eranga Dissa.. 5

一个值得注意的差异是Singletons带来的不同实例化.

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


归档时间:

查看次数:

475110 次

最近记录:

1 年,2 月 前