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

为什么您需要存储对单例的引用,而您始终可以通过静态 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

您的问题是单例初始化程序是相互依赖的。

打破这一点的一种方法是在初始化完成之前分配静态单例字段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

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

我展示了这个想法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 回答