8

コンピュータービジョンアプリケーションを開発していますが、分類子クラスが必要になります。このクラスは、アプリケーションの実行ごとに不変であり、初期化時にディスクからトレーニング済みデータをロードします。プログラム全体が同じトレーニング済みデータにアクセスできるようにしたいので、ロードされたディスクからのリロードをブロックしたいと思います。

私が考えていたのは、静的クラスまたはシングルトンのいずれかを使用することでした。コンパイル時にデータファイルへのパスがわからないため、静的クラスにデータをロードする方法がわかりません。これはプログラム引数になります。そこでシングルトンパターンを考えていたのですが、動的に初期化する方法がわかりません。

私のアイデアは以下を使用することでした:

class Singleton {
    private static Singleton instance;
    private Singleton() { ... }
    private static SomeDataObject data;

    public static Singleton getInstance() {
        if(instance == null)
            instance = new Singleton();

            return instance;
    }

    public static init(string dataPath){
        if(data == null)
             loadDataFromFile(dataPath)
    }
}

どのメソッドが最初に呼び出されるかを制御できないため、これは機能しません。

最初にデータを使用してインスタンスを作成し、それを必要とするすべてのクラスとメソッドに渡すのが適切な方法であることはわかっていますが、それは実際には一般的な解決策ではありません。自分のコードでClassifierへのすべての呼び出しを追跡できますが、コードをAPIとして作成する場合、これは問題になります。

要するに、実行時にシングルトンを初期化する方法は?

4

2 に答える 2

8

あなたがやりたいことが(正確に)うまくいくとは思いません。

以下はうまくいくでしょう:

public static void main(String[] args)
{
  Singleton.init("somepath");
  ...
  Singleton.getInstance().doingStuff();
  ...
}

より良い実装は次のとおりNullPointerExceptionです。init

private static Singleton instance;
private SomeDataObject data;

private Singleton(String path) { loadDataFromFile(path); ... }

public static Singleton getInstance() {
   return instance;
}

public static void init(String dataPath){
   instance = new Singleton(dataPath);
}

次に、次のとおりです。

class Main
{
  public static void main(String[] args)
  {
    Singleton.currentPath = "somepath";
    ...
  }
}

class Singleton
{
  public static String currentPath = null;
  private static Singleton instance;
  private SomeDataObject data;

  private Singleton(String path) { loadDataFromFile(path); ... }

  public static Singleton getInstance() {
     if(instance == null && currentPath != null)
        instance = new Singleton(currentPath);
     return instance;
  }
}

これは実際にはあまり解決しないと思います。

于 2013-02-19T17:04:31.627 に答える
0

私は、現在の勝者のソリューションよりも「より」スレッドセーフであり、同期がほとんど使用されていないものを使用しています。

import java.util.function.Supplier;

public class InitOnce {

/**
 * Marked as final to prevent JIT reordering
 */
private final Supplier<String> theArgs;

private InitOnce(Supplier<String> supplier) {
    super();
    this.theArgs = supplier;
}

/**
 * Uses the arguments to do something
 * 
 * @return
 */
public String doSomething() {
    return "Something : " + theArgs.get();
}

/**
 * Initializes all the things
 * 
 * @param someArgs
 */
public static synchronized void init(final Supplier<String> someArgs) {
    class InitOnceFactory implements Supplier<InitOnce> {
        private final InitOnce initOnceInstance = new InitOnce(someArgs);

        @Override
        public InitOnce get() {
            return initOnceInstance;
        }
    }

    if (!InitOnceFactory.class.isInstance(instance)) {
        instance = new InitOnceFactory();
    } else {
        throw new IllegalStateException("Already Initialized");
    }
}

private static Supplier<InitOnce> instance = new InitOnceHolder();

/**
 * Temp Placeholder supplier
 * 
 */
private static final class InitOnceHolder implements Supplier<InitOnce> {
    @Override
    public synchronized InitOnce get() {

        if (InitOnceHolder.class.isInstance(instance))
            throw new IllegalStateException("Not Initialized");

        return instance.get();
    }

}

/**
 * Returns the instance
 * 
 * @return
 */
public static final InitOnce getInstance() {
    return instance.get();
}
}
于 2016-08-18T14:40:26.173 に答える