design-patterns - whisky - singleton是什么




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

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

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


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

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

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


Singleton的实例化,它只是一个实例化的实例,因此Singleton中只有一个实例。

一个静态类不能被其他任何东西实例化。


静态类: -

  1. 您不能创建静态类的实例。

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

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

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

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

  6. 一个拥有所有静态方法的类。

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

辛格尔顿: -

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

  2. 当用户请求时,第一次创建单例实例。

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

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

  5. Singleton类不会说任何继承的限制。

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

  7. 方法可以被覆盖。

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

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


As I understand the difference between a Static class and non-Static Singleton class, the static is simply a non-instantiated "type" in C#, where the Singleton is a true "object". In other words, all the static members in a static class are assigned to the type but in the Singleton are housed under the object. But keep in mind, a static class still behaves like a reference type as its not a value type like a Struct.

That means when you create a Singleton, because the class itself isnt static but its member is, the advantage is the static member inside the Singleton that refers to itself is connected to an actual "object" rather than a hollow "type" of itself. That sort of clarifies now the difference between a Static and a Non-Static Singleton beyond its other features and memory usage, which is confusing for me.

Both use static members which are single copies of a member, but the Singleton wraps the referenced member around a true instantiated "object" who's address exists in addition to its static member. That object itself has properties wherein in can be passed around and referenced, adding value. The Static class is just a type so it doesn't exist except to point to its static members. That concept sort of cemented the purpose of the Singleton vs Static Class beyond the inheritance and other issues.


When I want class with full functionality, eg there are many methods and variables, I use singleton;

If I want class with only one or two methods in it, eg MailService class, which has only 1 method SendMail() I use static class and method.


一个。 序列化 - 静态成员属于该类,因此无法序列化。

湾 尽管我们已经将构造函数设置为私有,但静态成员变量仍将被传递给子类。

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


一个静态类只有静态方法,对此,一个更好的词将是“功能”。 体现在静态类中的设计风格纯粹是程序性的。

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


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

单态类对于依赖注入是可能的非常重要。

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

从测试的角度来看,Singleton是更好的方法。 与静态类不同,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()就很困难。 你可以用动力模拟来嘲弄静态,但并非所有的产品都可以使用它。


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


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

快速示例:

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

在很多情况下,这两者没有实际区别,特别是如果单例实例永远不会改变或缓慢变化,例如持有配置。

我认为最大的区别是单身仍然是一个普通的Java Bean,与专门的静态Java类相反。 正因为如此,单身人士在更多情况下被接受。 它实际上是默认的Spring Framework的实例化策略。 消费者可能会或可能不知道它是一个单身人士,它只是把它当作普通的Java bean来对待。 如果需求发生变化,而单例需要成为原型,就像我们在Spring中经常看到的那样,它可以完全无缝地完成,而不需要为消费者修改代码。

其他人之前提到,静态类应该是纯粹的过程化的,比如java.lang.Math。 在我看来,这样的一个类永远不应该被传递,他们绝不应该把静态final作为属性。 对于其他任何事情,使用单例,因为它更加灵活和易于维护。


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

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

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

*或者可能会在初次使用时实例化,具体取决于语言,我认为。


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

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

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

希望能帮到你..


我阅读以下内容并认为它也很有意义:

照顾生意

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

从“面向对象的思想过程”第4版。


扩展Jon Skeet的答案

单例和一堆静态方法之间的巨大差异是单例可以实现接口(或者从有用的基类派生,尽管这不是常见的IME),所以你可以将单例传递给它,就好像它是“另一个”实现一样。

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


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

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

静态类只允许静态方法。


这里有一篇很好的文章: http://javarevisited.blogspot.com.au/2013/03/difference-between-singleton-pattern-vs-static-class-java.html : 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来完成其他任何事情。

编辑







singleton