1

プログラムに無限再帰があり、クラスにフィールドがあり、そのフィールドに同じクラスがあります。それらはシングルトンですが、これが構築しない原因ではありません。私がプログラムを書いたところで、私は実際に位相配列を削除することはできません。

abstract class Phase{
  protected String phaseName;
  protected char[] keys;
  protected String[] commands;
  protected Phase[] phases;
  protected StringBuilder pattern;

}

class RemotePhase extends Phase{
  private static RemotePhase remotePhase;

  protected RemotePhase(){
    phaseName="Remote.";
    commands=new String[]{"Lock/unlock windows", "Toggle door", "Select dog menu"};
    setPattern();

    //Just below here starts an infinite loop
    phases=new Phase[]{FixWindows.getFixWindows(), ToggleDoor.getToggleDoor(), SelectDogPhase.getSelectDogPhase()};

  }

  public static RemotePhase getRemotePhase(){
    if(remotePhase==null){
      remotePhase=new RemotePhase();
    }
    return remotePhase;
  }
}

final class FixWindows extends Phase{
  private static FixWindows windows;
  private RemotePhase remotePhase;

  private FixWindows(){

    //execution keeps coming here as FixWindows object is never constructed
    remotePhase=RemotePhase.getRemotePhase();

  }

  public static FixWindows getFixWindows(){
    if(windows==null){
      windows=new FixWindows();
    }
    return windows;
  }
}

RemotePhase を静的クラスにして、FixWindows がそれをメンバーに使用しようとしましたが、抽象クラスの非静的メソッドをオーバーライドしようとして、非静的コンテキストで FixWindows からそれらを呼び出そうとすると、エラーが発生しました。ただし、RemotePhase を参照するためだけに追加のクラスを作成する必要があるため、静的にしないことを好みます。

ただし、これを機能させる方法はあります。ありがとう

4

3 に答える 3

4

static getter でいつでもアクセスできるのに、シングルトンへの参照を保存する必要があるのはなぜですか? RemotePhaseこれにより、 fromへの遅延アクセスが可能FixWindowsになり、循環依存が修正されます。したがって、最もクリーンな修正は、 のコンストラクター内でゲッターを呼び出さないことですFixWindows

final class FixWindows extends Phase{
  private static FixWindows windows;

  private FixWindows(){
      // does nothing but preventing external classes to instantiate it
  }

  public static synchronized FixWindows getFixWindows(){
    if(windows==null){
      windows=new FixWindows();
    }
    return windows;
  }

  public void methodThatRequiresTheRemotePhase(){
    doSomeStuff(RemotePhase.getRemotePhase());
  }
}

ところで、あなたのコードはスレッドセーフではないことに注意してください。ゲッターは同期する必要があります。

于 2016-08-07T01:56:20.997 に答える
1

これは、初期化ループを中断する方法に対する回答です。ただし、最初にシングルトン参照を保存する必要がないため、@Diciによる回答のRemotePhase方が優れています。

あなたの問題は、シングルトン初期化子が相互依存していることです。

これを打破する 1 つの方法は、in の初期化が完了するRemotePhase 前に静的シングルトン フィールドを割り当てることです。RemotePhaseこれにより、初期化が進行し、FixWindowsシ​​ングルトン オブジェクトが構築されたときに、(部分的に) 初期化されたシングルトン オブジェクトを見つけることができRemotePhaseます。

したがって、次のようなチャンスコード:

private RemotePhase() {
    phaseName = "Remote.";
    commands = new String[] { "Lock/unlock windows",
                              "Toggle door",
                              "Select dog menu" };
    setPattern();
}

private void init() {
    phases = new Phase[] { FixWindows.getFixWindows(),
                           ToggleDoor.getToggleDoor(),
                           SelectDogPhase.getSelectDogPhase() };
}

public static RemotePhase getRemotePhase() {
    if (remotePhase == null) {
        remotePhase = new RemotePhase(); // assigns partially initialized object
        remotePhase.init();              // completes initialization
    }
    return remotePhase;
}
于 2016-08-07T01:57:17.190 に答える
0

別のコンストラクターでコンストラクターを呼び出すことは避けてください。代わりにセッターを使用できます。

このアイデアを に示しFixWindowsます。他のサブクラスにも同じことを使用できます

abstract class Phase{
  protected String phaseName;
  protected char[] keys;
  protected String[] commands;
  protected Phase[] phases;
  protected StringBuilder pattern;

}

class RemotePhase extends Phase{
  private static RemotePhase remotePhase;

  protected RemotePhase(){
    phaseName="Remote.";
    commands=new String[]{"Lock/unlock windows", "Toggle door", "Select dog menu"};
    setPattern();

    //Just below here starts an infinite loop
    phases=new Phase[]{FixWindows.getFixWindows(this), ToggleDoor.getToggleDoor(), SelectDogPhase.getSelectDogPhase()};

  }

  public static RemotePhase getRemotePhase(){
    if(remotePhase==null){
      remotePhase=new RemotePhase();
    }
    return remotePhase;
  }
}

final class FixWindows extends Phase{
  private static FixWindows windows;
  private RemotePhase remotePhase;

  private FixWindows(){

    //execution keeps coming here as FixWindows object is never constructed
    //remotePhase=RemotePhase.getRemotePhase(); //shoud be deleted

  }

  public static FixWindows getFixWindows(remotePhase){
    if(windows==null){
      windows=new FixWindows();
      windows.setRemotePahse(remotePhase);
    }
    return windows;
  }
}
于 2016-08-07T01:57:53.260 に答える