如何初始化相互依赖的最终引用?
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;
}
我有一个 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;
}