繁体   English   中英

Java中的Singleton类如何处理这种情况?

[英]How to handle this situation for a Singleton class in Java?

我对如何在遵循Singleton模型的课程上进行以下操作有疑问。

我有这个原始的Singleton课程:

public class ThreadsManager {

    // I can have only one instance:
    private final static ThreadsManager instance = new ThreadsManager();

    // Private constructor:
    private ThreadsManager() {

    }

    public static ThreadsManager getInstance(){
        return instance;
    }
}

好的,这项工作很好,但是现在我必须对其进行修改,添加一个新属性(名为userName的字符串),该属性必须在构建单例对象时进行初始化,并且以后无法更改

所以我正在尝试做这样的事情:

public class ThreadsManager {

    private final static ThreadsManager instance = new ThreadsManager();

    private final static String userName;

    private ThreadsManager() {

    }

    public static ThreadsManager getInstance(String user){
        userName = user;
        return instance;
    }
}

所以我试图添加新的String userName变量,该变量是静态的 (对于该类一次)和最终的 (无法在第二次更改)

我的问题是Eclips将以下行标记为错误:

1) 私有最终静态String userName; 对我说:

 The blank final field userName may not have been initialized

似乎该字段将被初始化(我可以将其初始化为null,但是由于它是最终的...我以后不能在构造函数中初始化)

2) userName =用户; 对我说:

 The final field ThreadsManager.userName cannot be assigned

那么解决这种情况的最佳解决方案是什么?

如果我从userName变量定义中删除最终值 ,在我看来效果很好,但是可以更改此值,但是也许我根本无法为该字段提供setter方法,所以可以防止外部更改。

有什么想法吗?

我认为您想要一个带有论点的辛格尔顿。 这应该解释一下:

Java中带有参数的Singleton

由于此类是Singleton,因此名称实际上不应更改太多。 我建议只是将其作为类中的一个常数。 如果在不同情况下执行该程序时名称可能更改,请参见下面的解决方案2。

解决方案1:

public class ThreadsManager 
{
    private final static ThreadsManager instance = new ThreadsManager();
    private String userName;

    private ThreadsManager()
    {
       final String name = "Name";
       userName = name;
    }

    public static synchronized ThreadsManager getInstance(String user)
    {
       return instance;
    }
}

解决方案2:

如果您确实要设置Singleton的名称,并且每次执行程序时,名称可能会有所不同。 只需添加此方法:

private String userName = null;

// Can only be set after Singleton is created and when userName is null.
public void setName(String n)
{
   if(userName == null)
      userName = n;
}

不要让您的getInstance()方法具有参数, 这是一个错误的设计 每次有人或您尝试从您的类中获取实例时,他们/您都必须提供一个与99%的时间无关的参数。

如果您想要该类的实例的多个状态,则不会是单例,

您可以创建一个以user为键的Object的缓存,因此对于要求相同状态的对象仍然是单例

private final Map<String, ThreadsManager> instanceCache = Collections.synchronizedMap<String, ThreadsManager>();

此外,如果您有很多此类的状态,请确保您不会泄漏内存

您可以使用嵌套类来实现。

public class ThreadsManager {

    private static String userName;

    private ThreadsManager() {

    }

    public static ThreadsManager getInstance(String user){
        if (userName == null)
             userName = user;
        // the holder's instance is only initialised at this point, 
        // after userName is set.
        return Holder.instance;
    }

    static class Holder {
        private final static ThreadsManager instance = new ThreadsManager();
    }
}

首先:私有最终静态字符串userName只能在私有构造函数内部或在定义期间初始化。

其次,您可能最终得到一个null实例,因此您可能会执行以下操作:

public class ThreadsManager {

private final static ThreadsManager instance = new ThreadsManager();

private String userName;

private ThreadsManager() {

}

private ThreadsManager(String user) {
    userName = user;
}


public static ThreadsManager getInstance(String user){
    if(instance == null) {
        instance = new ThreadsManager(user);
    } else {
        Logger.getInstance().logWarning("User has already been set. Will continue with user ["+username+"].);
    }

    return instance;
    }
}

处理如何处理第二个用户名的处理需要一些思考。 总体上,您应该尝试使getInstance()方法参数保持空闲状态,因为它会导致上述问题。

怎么样

public class ThreadsManager {
    private final static ThreadsManager instance = new ThreadsManager();
    private static String userName;

public static synchronized ThreadsManager getInstance( String user ) {
    if ( username == null ) { userName = user; }
    return instance;
}

这样可以确保仅在第一次设置userName

但是,单身人士在随后的getInstance()上采用被忽略的参数可能会造成非常混乱的语义,具体取决于您的用例,甚至可能出现竞态条件。

干杯,

暂无
暂无

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

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