简体   繁体   English

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

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

I have some doubts regarding how to do the following operation on a class that follow the Singleton model. 我对如何在遵循Singleton模型的课程上进行以下操作有疑问。

I have this original Singleton class: 我有这个原始的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;
    }
}

Ok, this work well but now I have to modify it adding a new property (a String named userName ) that have to be initialized when the singleton object is build and that can not be changed at a later time 好的,这项工作很好,但是现在我必须对其进行修改,添加一个新属性(名为userName的字符串),该属性必须在构建单例对象时进行初始化,并且以后无法更改

So I am trying to do something like it: 所以我正在尝试做这样的事情:

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

So I am trying to add the new String userName variable that is static (once for the class) and final (can not be changed at a second time) 所以我试图添加新的String userName变量,该变量是静态的 (对于该类一次)和最终的 (无法在第二次更改)

My problem is that Eclips marks as an error the lines: 我的问题是Eclips将以下行标记为错误:

1) private final static String userName; 1) 私有最终静态String userName; saying to me that: 对我说:

 The blank final field userName may not have been initialized

It seems that would that the field will be initialized (I can initialize it to null but since it is final...I can't initialize later in the constructor) 似乎该字段将被初始化(我可以将其初始化为null,但是由于它是最终的...我以后不能在构造函数中初始化)

2) userName = user; 2) userName =用户; say to me that: 对我说:

 The final field ThreadsManager.userName cannot be assigned

So what is the best solution to handle this situation? 那么解决这种情况的最佳解决方案是什么?

If I remove the final from the userName variable definition it seems to me that work well but then I can change this value but maybe I simply can not provide the setter method for this field so I prevent external changes.... 如果我从userName变量定义中删除最终值 ,在我看来效果很好,但是可以更改此值,但是也许我根本无法为该字段提供setter方法,所以可以防止外部更改。

Some ideas? 有什么想法吗?

I think you want a singelton 'with arguments'. 我认为您想要一个带有论点的辛格尔顿。 This should explain it : 这应该解释一下:

Singleton with Arguments in Java Java中带有参数的Singleton

Since this class is a Singleton then the name shouldn't really change too much. 由于此类是Singleton,因此名称实际上不应更改太多。 I would suggest just keeping it as a constant inside the class. 我建议只是将其作为类中的一个常数。 If the name might change when the program is executed on different occasions then see Solution 2 below. 如果在不同情况下执行该程序时名称可能更改,请参见下面的解决方案2。

Solution 1: 解决方案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;
    }
}

Solution 2: 解决方案2:

If you really want to set the name of the Singleton and every time the program is execute the name might be different. 如果您确实要设置Singleton的名称,并且每次执行程序时,名称可能会有所不同。 Just add this method: 只需添加此方法:

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

Don't make your getInstance() method have a parameter, that is a bad design . 不要让您的getInstance()方法具有参数, 这是一个错误的设计 Every time someone, or you, tries to get an instance from your class they/you have to provide a parameter which will be 99% of the time be irrelevant. 每次有人或您尝试从您的类中获取实例时,他们/您都必须提供一个与99%的时间无关的参数。

It is not going to be singleton if you want multiple state of an instance of that class, 如果您想要该类的实例的多个状态,则不会是单例,

you could create a cache of Object keyed with user so it would still be singleton for same state asked 您可以创建一个以user为键的Object的缓存,因此对于要求相同状态的对象仍然是单例

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

Also make sure you don't leak memory if you have tons of states for this class 此外,如果您有很多此类的状态,请确保您不会泄漏内存

You can do it using a nested class. 您可以使用嵌套类来实现。

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();
    }
}

First of all: private final static String userName may only be initialized inside the private constructor or during definition. 首先:私有最终静态字符串userName只能在私有构造函数内部或在定义期间初始化。

Secondly You may end up with a null instance, so you might do something like this: 其次,您可能最终得到一个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;
    }
}

The handling of how to deal with a second user name handed needs some thinking. 处理如何处理第二个用户名的处理需要一些思考。 Overall you should try to keep the getInstance() method parameter free since it leads to the above mentioned problems. 总体上,您应该尝试使getInstance()方法参数保持空闲状态,因为它会导致上述问题。

How about 怎么样

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

That would ensure userName is only set the first time. 这样可以确保仅在第一次设置userName

It is, however, potentially very confusing semantics for a singleton to take a parameter that is ignored on subsequent getInstance() 's - possibly even race-condition-prone, depending on your use-case. 但是,单身人士在随后的getInstance()上采用被忽略的参数可能会造成非常混乱的语义,具体取决于您的用例,甚至可能出现竞态条件。

Cheers, 干杯,

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

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