说我有两个这样的课程
public class Foo
{
protected final Bar child;
public Foo()
{
child = new Bar(this);
}
}
public class Bar
{
protected final Foo parent;
public Bar(Foo parent)
{
this.parent = parent;
}
}
我想创建一个Foo
,Foo2
的子类,其子类为Bar2
,它是Bar
的子类。我可以这样做:
public class Foo
{
protected final Bar child;
public Foo()
{
child = new makeChild();
}
protected Bar makeChild()
{
return new Bar(this);
}
}
public class Foo2 extends Foo
{
@Override
protected Bar makeChild()
{
return new Bar2(this);
}
}
然而,this is supposed to be a very bad idea。但是这样的事情是行不通的:
public class Foo
{
protected final Bar child;
public Foo()
{
this(new Bar(this));
}
protected Foo(Bar child)
{
this.child = child;
}
}
因为new Bar(this)
在调用超类型构造函数之前引用this
。
我认为有两种方法可以解决这个问题:
1)我可以将成员设置为private和non-final,然后使setter在设置时抛出异常,但这看起来很笨拙,只能在运行时检测到任何编码问题。
2)我将Foo
构造函数作为参数使用Class
类型的Bar
对象,然后使用反射来调用该类的构造函数。然而,这似乎是我正在努力做的重量级。
我缺少任何编码技术或设计模式吗?
答案 0 :(得分:2)
我缺少任何编码技术或设计模式吗?
我想到了dependency injection模式。只需从构造函数中取出参数,创建构成上面接口类的类型,然后在需要时注入适当的具体类型。
Foo界面
interface Foo {
public void setBar(Bar bar);
public Bar getBar();
}
条形码界面
interface Bar {
public void setFoo(Foo foo);
public Foo getFoo();
}
我一直在寻找使用Guice或类似的东西来进一步解耦并自动进行注射。
答案 1 :(得分:1)
你的问题是关于循环参考的简单问题。
首先,您应该设计类以避免循环引用,原因有多种here
接下来,如果您没有选项,那么最佳解决方案是使用“依赖注入”。为什么?这样想:
因此,依赖注射可以安全救援。
答案 2 :(得分:0)
其中一个选择是为初始化创建一个单独的函数,并在子类ctor中调用init方法:
e.g。
class Foo {
private Bar child;
public Foo() {
initWithChild(new Bar(this));
}
protected final void initWithChild(Bar child) {
this.child = child;
}
}
class Foo2 {
public Foo2() {
initWithChild(new Bar2(this));
}
}
当然,它假设Foo和Bar是耦合的,依靠Foo来实例化Bar是合理的。但是在大多数情况下,您应该考虑通过DI框架向Bar注入Bar。
在评论中你提到了最终的需要。
虽然我不认为在成员var现在是私有的情况下非终结是一个大问题,但这是另一种方法(实际上与上述相似),你可以考虑 IF 初始化工作就像你的问题一样简单:
class Foo {
protected final Bar child;
public Foo() {
this.child = new Bar(this);
}
}
class Foo2 {
public Foo2() {
this.child = new Bar2(this);
}
}
没有测试过代码,但我相信它应该可行:P