Java中带有参数的Singleton

我正在阅读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的渴望已经引发了一场争论的风暴。让我解释一下我的动机,并希望有人可以提出一个更好的主意。我正在使用网格计算框架来并行执行任务。总的来说,我有这样的事情:


// 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;

    }


如您所见,即使在这里,我仍然遇到这样的问题:在传递第一个文件路径之后,传递不同的文件路径没有任何意义。这就是为什么我喜欢答案中张贴的商店的想法。无论如何,我没有在run方法中包含用于加载文件的逻辑,而是希望将此逻辑抽象为Singleton类。我不会再提供另一个示例,但是希望您能理解。请让我听听您的想法,以更优雅的方式完成我要尝试的工作。再次感谢你!


qq_花开花谢_0
浏览 671回答 3
3回答

繁花不似锦

我会很清楚地指出:具有参数的单例不是单例。根据定义,单例是您希望被实例化的对象不超过一次。如果您试图将参数提供给构造函数,那么单例的意义是什么?您有两个选择。如果您希望用一些数据初始化单例,则可以在实例化之后用数据加载它,如下所示: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无论如何,实例化总是没有参数的。否则,您的单身人士将不是单身人士。

森林海

我认为您需要像工厂这样的东西来实例化和重用各种参数的对象。可以通过使用同步对象HashMap或ConcurrentHashMap将参数(Integer例如)映射到“单个”可参数化类来实现。尽管您可能会改用常规的非单例类(例如,需要10.000个不同参数化的单例)。这是此类商店的示例:public final class UsefulObjFactory {&nbsp; &nbsp; private static Map<Integer, UsefulObj> store =&nbsp; &nbsp; &nbsp; &nbsp; new HashMap<Integer, UsefulObj>();&nbsp; &nbsp; public static final class UsefulObj {&nbsp; &nbsp; &nbsp; &nbsp; private UsefulObj(int parameter) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // init&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; public void someUsefulMethod() {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // some useful operation&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }&nbsp; &nbsp; public static UsefulObj get(int parameter) {&nbsp; &nbsp; &nbsp; &nbsp; synchronized (store) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; UsefulObj result = store.get(parameter);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; if (result == null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; result = new UsefulObj(parameter);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; store.put(parameter, result);&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; return result;&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; }}为了进一步推动它enum,尽管只允许使用固定数量的静态变体,但是Java 也可以视为(或用作)参数化的单例。但是,如果您需要分布式1解决方案,请考虑一些横向缓存解决方案。例如:EHCache,Terracotta等。1可能跨越多台计算机上的多个VM。

猛跑小猪

您可以添加可配置的初始化方法,以将实例化与获取分开。public class Singleton {&nbsp; &nbsp; private static Singleton singleton = null;&nbsp; &nbsp; private final int x;&nbsp; &nbsp; private Singleton(int x) {&nbsp; &nbsp; &nbsp; &nbsp; this.x = x;&nbsp; &nbsp; }&nbsp; &nbsp; public static Singleton getInstance() {&nbsp; &nbsp; &nbsp; &nbsp; if(singleton == null) {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new AssertionError("You have to call init first");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; return singleton;&nbsp; &nbsp; }&nbsp; &nbsp; public synchronized static Singleton init(int x) {&nbsp; &nbsp; &nbsp; &nbsp; if (singleton != null)&nbsp; &nbsp; &nbsp; &nbsp; {&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // in my opinion this is optional, but for the purists it ensures&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // that you only ever get the same instance when you call getInstance&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; throw new AssertionError("You already initialized me");&nbsp; &nbsp; &nbsp; &nbsp; }&nbsp; &nbsp; &nbsp; &nbsp; singleton = new Singleton(x);&nbsp; &nbsp; &nbsp; &nbsp; return singleton;&nbsp; &nbsp; }}然后,您可以调用Singleton.init(123)一次进行配置,例如在应用启动时。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java