java - Java中带参数的单例

标签 java oop singleton anti-patterns

我在阅读 Wikipedia 上的 Singleton 文章时遇到了这个例子:

public class Singleton {
    // Private constructor prevents instantiation from other classes
    private Singleton() {}

    /**
     * SingletonHolder is loaded on the first execution of Singleton.getInstance() 
     * or the first access to SingletonHolder.INSTANCE, not before.
     */
    private static class SingletonHolder { 
        private static final Singleton INSTANCE = new Singleton();
    }

    public static Singleton getInstance() {
        return SingletonHolder.INSTANCE;
    }
}

虽然我真的很喜欢这个 Singleton 的行为方式,但我不知道如何调整它以将参数合并到构造函数中。在 Java 中执行此操作的首选方法是什么?我必须做这样的事情吗?

public class Singleton
{
    private static Singleton singleton = null;  
    private final int x;

    private Singleton(int x) {
        this.x = x;
    }

    public synchronized static Singleton getInstance(int x) {
        if(singleton == null) singleton = new Singleton(x);
        return singleton;
    }
}

谢谢!


编辑:我想我对使用 Singleton 的渴望引发了一场争议 Storm 。让我解释一下我的动机,希望有人能提出一个更好的主意。我正在使用网格计算框架来并行执行任务。一般来说,我有这样的事情:

// AbstractTask implements Serializable
public class Task extends AbstractTask
{
    private final ReferenceToReallyBigObject object;

    public Task(ReferenceToReallyBigObject object)
    {
        this.object = object;
    }

    public void run()
    {
        // Do some stuff with the object (which is immutable).
    }
}

发生的情况是,即使我只是将数据的引用传递给所有任务,但当任务被序列化时,数据会被一遍又一遍地复制。我想做的是在所有任务之间共享对象。当然,我可能会像这样修改这个类:

// AbstractTask implements Serializable
public class Task extends AbstractTask
{
    private static ReferenceToReallyBigObject object = null;

    private final String filePath;

    public Task(String filePath)
    {
        this.filePath = filePath;
    }

    public void run()
    {
        synchronized(this)
        {
            if(object == null)
            {
                ObjectReader reader = new ObjectReader(filePath);
                object = reader.read();
            }
        }

        // Do some stuff with the object (which is immutable).
    }
}

如您所见,即使在这里我也有一个问题,即在传递第一个文件路径后传递不同的文件路径没有任何意义。这就是为什么我喜欢在答案中发布的 store 的想法。无论如何,我不想在 run 方法中包含加载文件的逻辑,而是想将此逻辑抽象为一个 Singleton 类。我不会再举一个例子,但我希望你能明白。请让我听听您的想法,以更优雅的方式完成我正在尝试做的事情。再次感谢!

最佳答案

我的观点很明确:带参数的单例不是单例

根据定义,单例是您希望实例化不超过一次的对象。如果您尝试将参数提供给构造函数,那么单例的意义何在?

你有两个选择。如果你想用一些数据初始化你的单例,你可以在实例化之后用数据加载它,像这样:

SingletonObj singleton = SingletonObj.getInstance();
singleton.init(paramA, paramB); // init the object with data

如果您的单例正在执行的操作是重复的,并且每次使用不同的参数,您不妨将参数传递给正在执行的 main 方法:

SingletonObj singleton = SingletonObj.getInstance();
singleton.doSomething(paramA, paramB); // pass parameters on execution

在任何情况下,实例化始终是无参数的。否则你的单例就不是单例。

关于java - Java中带参数的单例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1050991/

相关文章:

java - 如何使用JSch与子系统NETCONF建立SSH连接

Java静态关键字的使用

c++ - 为什么在 C++ 中,Visual Studio 将我的类构造函数描述为具有 "2+ Overloads"?

JavaScript 单例 : access outer attribute from inner function

java - 如果输入一个数字,同时将每个数字加上 n 次幂,对应于下面给出的公式,如何对数字进行求和?

java - 在 Java 中解析没有 DOM 的高度嵌套 XML

java - Java中如何调用同一个类的方法?

javascript - 有人可以澄清原型(prototype)和构造函数这两个词的歧义吗?

ios - 如何使用swift在单个数组中对具有日期属性的多个类对象进行排序?

javascript - Electron:在主渲染器和渲染器中使用相同的单例