【问题标题】:Infinite recursion composition class无限递归组合类
【发布时间】:2016-08-07 01:43:17
【问题描述】:

我的程序中有一个无限递归,我在一个类中有一个字段,该字段在其字段中具有相同的类。它们是单例,但这不是导致它们不构造的原因。顺便说一句,我编写程序实际上无法删除阶段数组。

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。

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

【问题讨论】:

  • 这是一个无限递归而不是无限循环。
  • 更改 FixWindows 构造函数并传递 RemotePhase (this) 以在 getFixWindows 中构建它,或者只是在 getFixWindows 中设置 remotePhase。尽量避免在其他构造函数中调用构造函数。你的静态方法很适合设置这些东西
  • 请出示一下好吗
  • 查看this answer 了解实现单例的简单方法
  • 谢谢,提醒我在一篇文章中看到了这个策略

标签: java oop design-patterns object-oriented-analysis infinite-recursion


【解决方案1】:

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

【讨论】:

  • @DannyP。我用一个例子和一个关于线程安全的警告编辑了我的帖子
  • 好的,我现在可以更好地理解了......当我编写代码来设置阶段的自动执行时,我最终不得不为每个阶段存储一个阶段数组。跨度>
  • 我不知道你在做什么,但我建议在使用这么多单例时三思而后行。通常你会使用单例主要是为了避免多次加载或序列化非常大的资源(或线程池,类似的东西),但你似乎没有这样做,所以我想知道这种复杂性是否有用
  • 好吧,我没有使用它,我只是有一个由另一个映射返回的映射,它是通过循环遍历这些数组来设置的:名称、键和阶段。我只想对阶段和其他类使用一个对象并进行跟踪。
【解决方案2】:

这是关于如何打破初始化循环的答案。不过Answer by @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;
}

【讨论】:

    【解决方案3】:

    你应该避免在另一个中调用构造函数。您可以改用 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;
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-01-08
      • 1970-01-01
      • 2015-09-19
      • 2013-07-30
      • 1970-01-01
      • 2014-11-26
      • 2016-09-11
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多