如何初始化相互依赖的最终引用?

How can I initialize interdependent final references?

我有一个 class 和一个工厂函数,用于创建扩展 class 的新匿名 class 对象。然而,匿名 class 对象都有一个方法,其中有对其他对象的引用。在我的完整程序中,我需要它来创建和组合解析器,但我在这里精简了代码。

class Base{
    public Base run(){
        return null;
    }   
    static Base factory(final Base n){
        return new Base(){
            public Base run(){
                return n;
            }
        };
    }
}

public class CircularReferences{
    public static void main(String args[]){
        final Base a, b;
        a = Base.factory(b);
        b = Base.factory(a);
    }
}

我得到 CircularReferences.java:17; error: variable b might not have been initialized。没错,它不是,但我不能为这些变量预留 space,然后使用对这些 space 的引用来初始化它们,这些变量将在它们出现之前填充正确的值实际使用?我可以将 new 与构造函数分开使用吗?我如何创建这些变量以便它们相互引用?

快速回答是你不能这样做。如果你绝对必须做这样的事情,那么在 class 上使用私有 setter 并在它们构造后将它们绑定在一起(即使用强制不变性而不是最终字段)。希望很明显我认为这不是一个好主意 - 我只是想在回答我真正想要的方式之前提供对您实际问题的答案。

好的 - 现在已经不碍事了,这里是真正需要的回应:

一般来说,这种情况强烈表明需要重构来分离关注点。换句话说,基地 class 可能试图为太多事情负责。

我意识到这个例子是人为设计的,但想想哪些功能需要循环依赖,然后将 那个 功能分解成一个单独的 class/object 然后通过给两个 Base 构造函数。

在复杂的架构中,循环依赖链可能会变得相当大,但严格强制使用 final 字段是寻找此类重构机会的好方法。

如果您有具体示例,我很乐意提供一些重构建议来帮助您打破这样的依赖关系。


提供了具体示例 - 这是我的建议:

似乎存在基于令牌获取适当的 ParseStrategy 的问题。一个 ParseStrategyProvider。所以会有一个 TopLevelParseStrategy 读取下一个标记,查找适当的解析策略并执行它。

TopLevelParseStrategy 将保留对 ParseStrategyProvider 的最终引用。

然后 ParseStrategyProvider 需要有一个注册方法(即 registerStrategy(token, parseStrategy) )。

这在功能上与通过私有 setter 强制不变性执行此操作没有太大区别(registerStrategy 方法的所有意图和目的与私有 setter 相同),但是设计更具可扩展性。

所以你有:

public ParseStrategy createParser(){
  ParseStrategyProvider provider = ParseStrategyProvider.create();
  TopLevelParseStrategy topLevel = new TopLevelParseStrategy(provider);
  provider.registerStrategy("(", topLevel);

  // create and register all of your other parse strategies

  return topLevel;
}