无限递归组合class

Infinite recursion composition class

我的程序中有一个无限递归,我在 class 中有一个字段,它的字段中有相同的 class。他们是单身人士,但这并不是他们不建造的原因。顺便说一句,我编写程序实际上无法删除相数组。

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 设置为静态 class 并且 FixWindows 将其用于其成员,但是我 运行 在尝试覆盖抽象 class 的非静态方法时遇到了错误,并尝试在非静态上下文中从 FixWindows 调用它们。不过,我不想让它成为静态的,因为我必须再做一个 class 才能引用 RemotePhase。

尽管有任何方法可以使这项工作正常进行。谢谢

为什么您需要存储对单例的引用,而您始终可以通过静态 getter 访问它?这将允许从 FixWindows 延迟访问 RemotePhase,并修复您的循环依赖。因此,最干净的修复方法就是不要在 FixWindows.

的构造函数中调用 getter
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());
  }
}

顺便提一下,我要警告你,你的代码不是线程安全的。您的 getter 应该同步。

这是对如何打破初始化循环的回答。然而, 更好,因为您首先不需要存储对 RemotePhase 的单例引用。

你的问题是单例初始化器是相互依赖的。

打破它的一种方法是在 RemotePhase 之前分配 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;
}

你应该避免在另一个中调用构造函数。您可以改用设置器。

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