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

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


当前回答

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

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

其他回答

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

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

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

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

与静态类的区别

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

单例的优点

如果您需要维护状态,那么单例模式比静态类更好,因为在静态类中维护状态会导致错误,特别是在并发环境中,如果没有多个线程进行适当的同步并行修改,则可能会导致竞争条件。如果Singleton类是一个沉重的对象,那么它可以被延迟加载,但静态类没有这样的优势,总是急切地加载。使用singleton,您可以使用继承和多态性来扩展基类、实现接口并提供不同的实现。由于Java中的静态方法不能被重写,它们会导致灵活性。另一方面,您可以通过扩展singleton类来重写它中定义的方法。

静态类的缺点

为单例编写单元测试比静态类更容易,因为只要需要单例,就可以传递模拟对象。

静态类的优点

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

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

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

详细描述每一个都太冗长了,所以我只需要链接到一篇好文章-你想知道的关于Singleton的所有信息

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

我头脑中的不同是实现面向对象编程(Singleton/Prototype)或函数编程(Static)。

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

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

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

从测试角度来看,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模拟静态,但并非所有产品都可以使用它。