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

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


当前回答

我同意这个定义:

单词“single”表示整个应用程序生命周期中的单个对象循环,因此范围在应用程序级别。静态不具有任何Object指针,因此作用域位于AppDomain级别。此外,两者都应实现为线程安全。

你可以发现其他有趣的区别:Singleton模式与静态类

其他回答

Singleton的被实例化。只是只有一个实例被创建过,因此在Singleton中只有一个。

另一方面,静态类无法实例化。

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

在下面的示例中,我将对此进行说明。假设您有一个使用getPrice()方法的方法isGoodPrice(。

提供getPrice功能的singleton:

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模拟静态,但并非所有产品都可以使用它。

扩展Jon Skeet的答案

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

当单元测试一个类时,单体更容易处理。无论您将单例作为参数(构造函数、setter或方法)传递到何处,您都可以替换单例的一个被嘲笑或存根的版本。

我同意这个定义:

单词“single”表示整个应用程序生命周期中的单个对象循环,因此范围在应用程序级别。静态不具有任何Object指针,因此作用域位于AppDomain级别。此外,两者都应实现为线程安全。

你可以发现其他有趣的区别:Singleton模式与静态类

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

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

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

除非你想要一个没有任何装置的整个应用程序,所有地方都是静态的-那么单例对于这些情况是有意义的,因为我们不能依靠缺少人为错误作为唯一的保证不会覆盖某些内容。

但要注意,单身汉并不能保证不会在任何地方生活。你的网络处理程序本身也可能依赖于其他单身者,等等。。。了不起的

而且,目前还没有编译器可以确保在编译时,单例是所有状态所在的地方,或者任何其他这样的想法所在的地方。在具有单例的类上可以有一百个静态变量。单例可以访问静态变量。编译器不会在意。

因此,我要提醒任何人,不要假设使用单例可以保证任何有关州生活的信息。它唯一的保证就是它是其类的唯一实例。这也是它唯一的优势。

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

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

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