繁体   English   中英

在不使用静态方法的情况下制作类单例

[英]Making a class singleton without using static method

我需要创建一个单例类而不保留静态方法。

我怎样才能做到这一点?

用一个实例创建一个枚举

enum Singleton {
    INSTANCE;

    private Field field = VALUE;
    public Value method(Arg arg) { /* some code */ }
}

// You can use
Value v = Singleton.INSTANCE.method(arg);

编辑: Java 枚举教程向您展示了如何向枚举添加字段和方法。


顺便说一句:通常当您可以使用单例时,您实际上并不需要单例,因为实用程序类会做同样的事情。 更短的版本只是

enum Utility {;
    private static Field field = VALUE;
    public static Value method(Arg arg) { /* some code */ }
}

// You can use
Value v = Utility.method(arg);

单例的用处在于它们实现接口时。 这对于使用依赖注入进行测试特别有用。 (在单元测试中使用单例或实用程序类替换的弱点之一)

例如

interface TimeService {
    public long currentTimeMS();
}

// used when running the program in production.
enum VanillaTimeService implements TimeService {
    INSTANCE;
    public long currentTimeMS() { return System.currentTimeMS(); }
}

// used in testing.
class FixedTimeService implements TimeService {
    private long currentTimeMS = 0;
    public void currentTimeMS(long currentTimeMS) { this.currentTimeMS = currentTimeMS; }
    public long currentTimeMS() { return currentTimeMS; }
}

如您所见,如果您的代码在任何地方都使用 TimeService,您可以注入VanillaTimeService.INSTANCEnew FixedTimeService() ,您可以在其中从外部控制时间,即每次运行测试时您的时间戳都相同。

简而言之,如果您不需要单例来实现接口,那么您可能只需要一个实用程序类。

public class Singleton {
    public static final Singleton instance = new Singleton();
    private Singleton() {}
    public void foo() {}
}

然后使用

Singleton.instance.foo();

另一种方法是单例持有者习惯用法,它提供按需初始化:

public class Something {
        private Something() {
        }
 
        private static class LazyHolder {
                public static final Something INSTANCE = new Something();
        }
 
        public static Something getInstance() {
                return LazyHolder.INSTANCE;
        }
}

请注意,应该尽可能避免像这样的独立单例,因为它会提升全局状态,导致难以进行单元测试的代码,并且依赖于单个类加载器上下文来列举一些可能的缺点。

按照“Effective Java”第二版中的 Joshua Bloch 枚举方法进行操作。 这是创建单身人士的最佳方式。

我不明白为什么会出现这么多。 单例不是一种名誉扫地的设计模式吗? 今天,GoF 将把它投票离开该岛。

您可以使用 IoC 容器之一(例如Google Guice )并将您的类用作单例(急切或懒惰 - 这取决于您的需要)。 由于实例化是由 IoC 框架控制的,因此它既简单又灵活——例如,如果您稍后决定让您的类不是单例,则不需要任何代码更改。

使用对象工厂,从这个工厂获取你的单例对象。

ObjectFactory factory;
....
MySingletonObject obj = factory.getInstance(MySingletonObject.class);

当然,有很多框架可以帮助您实现这一目标。 spring 框架是一个流行的选择。

从构造函数中,您需要检查某处是否已经存在该类的实例。 因此,您需要在静态变量或类中存储对单例实例的引用。 然后在单例的构造函数中,我总是会检查是否存在单例类的现有实例。 如果是,我不会做任何事情,否则我会创建它并设置参考。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM