为了账号安全,请及时绑定邮箱和手机立即绑定

Java中带有参数的Singleton

Java中带有参数的Singleton

qq_花开花谢_0 2019-10-15 14:00:23
我正在阅读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 Serializablepublic 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 Serializablepublic class Task extends AbstractTask{    private static ReferenceToReallyBigObject object = null;    private final String filePath;    public Task(String filePath)    {        this.filePath = filePath;    }如您所见,即使在这里,我仍然遇到这样的问题:在传递第一个文件路径之后,传递不同的文件路径没有任何意义。这就是为什么我喜欢答案中张贴的商店的想法。无论如何,我没有在run方法中包含用于加载文件的逻辑,而是希望将此逻辑抽象为Singleton类。我不会再提供另一个示例,但是希望您能理解。请让我听听您的想法,以更优雅的方式完成我要尝试的工作。再次感谢你!
查看完整描述

3 回答

?
繁花不似锦

TA贡献1851条经验 获得超4个赞

我会很清楚地指出:具有参数的单例不是单例。


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


您有两个选择。如果您希望用一些数据初始化单例,则可以在实例化之后用数据加载它,如下所示:


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

无论如何,实例化总是没有参数的。否则,您的单身人士将不是单身人士。


查看完整回答
反对 回复 2019-10-15
?
森林海

TA贡献2011条经验 获得超2个赞

我认为您需要像工厂这样的东西来实例化和重用各种参数的对象。可以通过使用同步对象HashMap或ConcurrentHashMap将参数(Integer例如)映射到“单个”可参数化类来实现。


尽管您可能会改用常规的非单例类(例如,需要10.000个不同参数化的单例)。


这是此类商店的示例:


public final class UsefulObjFactory {


    private static Map<Integer, UsefulObj> store =

        new HashMap<Integer, UsefulObj>();


    public static final class UsefulObj {

        private UsefulObj(int parameter) {

            // init

        }

        public void someUsefulMethod() {

            // some useful operation

        }

    }


    public static UsefulObj get(int parameter) {

        synchronized (store) {

            UsefulObj result = store.get(parameter);

            if (result == null) {

                result = new UsefulObj(parameter);

                store.put(parameter, result);

            }

            return result;

        }

    }

}

为了进一步推动它enum,尽管只允许使用固定数量的静态变体,但是Java 也可以视为(或用作)参数化的单例。


但是,如果您需要分布式1解决方案,请考虑一些横向缓存解决方案。例如:EHCache,Terracotta等。


1可能跨越多台计算机上的多个VM。


查看完整回答
反对 回复 2019-10-15
?
猛跑小猪

TA贡献1858条经验 获得超8个赞

您可以添加可配置的初始化方法,以将实例化与获取分开。


public class Singleton {

    private static Singleton singleton = null;

    private final int x;


    private Singleton(int x) {

        this.x = x;

    }


    public static Singleton getInstance() {

        if(singleton == null) {

            throw new AssertionError("You have to call init first");

        }


        return singleton;

    }


    public synchronized static Singleton init(int x) {

        if (singleton != null)

        {

            // in my opinion this is optional, but for the purists it ensures

            // that you only ever get the same instance when you call getInstance

            throw new AssertionError("You already initialized me");

        }


        singleton = new Singleton(x);

        return singleton;

    }


}

然后,您可以调用Singleton.init(123)一次进行配置,例如在应用启动时。


查看完整回答
反对 回复 2019-10-15
  • 3 回答
  • 0 关注
  • 659 浏览

添加回答

举报

0/150
提交
取消
意见反馈 帮助中心 APP下载
官方微信