【问题标题】:Singleton Pattern: getInstance() vs Passing the singleton object?单例模式:getInstance() 与传递单例对象?
【发布时间】:2019-10-24 22:56:38
【问题描述】:

什么是使用单例模式的正确/最流行的方式。

  1. 限制数量。调用 getInstance(),最好只调用一次,然后在实例化期间将对象传递给其他类?
class SingletonClass {
// Implementataion
}

class MainClass {
    private SingletonClass singletonClassObject;

    public MainClass() {
        singletonClassObject = SingletonClass.getInstance();
        new SomeClass(singletonClassObject).doSomething();
        new SomeOtherClass(singletonClassObject).doSomethingElse();
    }
}

class SomeClass {
    private SingletonClass singletonClassObject;

    public SomeClass(SingletonClass singletonClassObject) {
        this.singletonClassObject = singletonClassObject;
    }

    public void doSomething() {
        System.out.println(singletonClassObject.getStuff());
    }
}

class SomeOtherClass {
    private SingletonClass singletonClassObject;

    public SomeOtherClass(SingletonClass singletonClassObject) {
        this.singletonClassObject = singletonClassObject;
    }

    public void doSomethingElse() {
        System.out.println(singletonClassObject.getStuff());
    }
}

  1. 不要传递单例对象。而是调用获取每个类中的对象引用并将引用保存为实例变量并在需要时使用它。
class SingletonClass {
// Implementataion
}

class MainClass {
    public MainClass() {
        new SomeClass().doSomething();
        new SomeOtherClass().doSomethingElse();
    }
}

class SomeClass {
    private SingletonClass singletonClassObject;

    public SomeClass() {
        singletonClassObject = SingletonClass.getInstance();
    }

    public void doSomething() {
        System.out.println(singletonClassObject.getStuff());
    }
}

class SomeOtherClass {
    private SingletonClass singletonClassObject;

    public SomeOtherClass() {
        singletonClassObject = SingletonClass.getInstance();
    }

    public void doSomethingElse() {
        System.out.println(singletonClassObject.getStuff());
    }
}

  1. 甚至不要将引用保存为实例变量,而是在需要对象的任何地方使用 SingletonClass.getInstance()。
class SingletonClass {
// Implementataion
}

class MainClass {
    public MainClass() {
        new SomeClass().doSomething();
        new SomeOtherClass().doSomethingElse();
    }
}

class SomeClass {
    public SomeClass() {
    }

    public void doSomething() {
        System.out.println(SingletonClass.getInstance().getStuff());
    }
}

class SomeOtherClass {
    public SomeOtherClass() {
    }

    public void doSomethingElse() {
        System.out.println(SingletonClass.getInstance().getStuff());
    }
}

这些方法如何相互比较 w.r.t.更好的设计,可测试性等?哪个更好?为什么?

【问题讨论】:

  • 如果要将对象传递给方法,为什么需要单例?
  • 可能有多种原因。例如此类的每个实例都包含大量资源,而您的用例只能使用一个对象

标签: java oop design-patterns singleton


【解决方案1】:

如果我们暂时假设SingletonClass 不是单例并且我们没有通过调用static 方法获得实例,我们将面临另一个问题,如何将这些类链接在一起。这个问题由Dependency Injection 解决,这个概念在这里有很好的描述:

阅读以上内容后,应该很容易选择选项.1,其中所有类都在构造函数中引用所需的依赖项。您甚至可以为您需要的行为创建一个interface,并在SingletonClass 中实现它。现在你看到了,类实现Singleton 模式这一事实并没有使它特别,我们应该像其他类一样注入它们。使用DI 的所有好处都可以应用于您的班级。

只需将其与.3 进行比较,您就需要在需要模拟的地方编写一个测试。如果是.1,这将是更不愉快的任务。

【讨论】:

  • 没错。这就是所有众所周知的 IOC 容器的设计方式。 Singleton 由配置定义,而不是硬编码 这种行为。
【解决方案2】:

这样看:您质疑编译器识别静态最终引用可以编译为内联引用的能力。

我猜编译器会将 getInstance() 转换为内联引用。我不太相信编译器会在您通过值传递引用时识别出您有意为自己创建额外的工作,并且当您传递它时它会在堆栈上创建额外的引用。

我的猜测是 getInstance() 会更有效率。

【讨论】:

  • 我越想这个,我就越相信答案是正确的。 Java 编译器在计算内联引用方面非常出色,但是......这里是踢球者......在 Java 中作为方法参数的引用总是按值传递,这意味着它应该在堆。编译器可能非常出色,它会弄清楚您要做什么并打破自己的规则,但规则按值表示,这意味着额外的堆栈分配。
  • 好吧,我并没有真正比较性能本身。从设计的角度来看,我更感兴趣,比如哪种方法更易于维护、可读、可测试等等。以及业界普遍采用哪种方式。
  • 我不确定还有什么比能够查看对象的任何单一用途并立即知道它是什么以及它是如何设计的更易于维护的。 :D
  • 我能想象到的一个例外是 Singleton 类位于冗长的外观之后,就像标准的 Spring bean 一样。我会想象每次使用 bean 时都输入 Spring getter 会是一个令人望而却步的输入(我知道你可以重新连接 Spring 以使用非单例实现,但一般来说没有人这样做)..
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-09-07
  • 2015-08-17
相关资源
最近更新 更多