1

このような2つのクラスがあるとします

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子として持つのサブクラスを作成したいと考えています。私はこのようにすることができます:Bar2Bar

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);
    }
}

しかし、これは非常に悪い考えです。しかし、このようなものはうまくいきません:

public class Foo
{
    protected final Bar child;

    public Foo()
    {
        this(new Bar(this));
    }

    protected Foo(Bar child)
    {
        this.child = child;
    }
}

スーパータイプコンストラクターが呼び出される前にnew Bar(this)参照するためです。this

これに対処するには、次の 2 つの方法があります。

1) メンバーをプライベートで非最終的なものにしてから、既に設定されている場合に例外をスローするセッターを作成できますが、それは不器用に思え、実行時にコーディングの問題のみを検出します。

2)コンストラクターが使用する型のオブジェクトをFooパラメーターとして取り、リフレクションを使用してそのクラスのコンストラクターを呼び出します。しかし、それは私がやろうとしていることにとっては重いようです。ClassBar

不足しているコーディング手法やデザインパターンはありますか?

4

3 に答える 3

2

不足しているコーディング手法やデザインパターンはありますか?

依存性注入パターンが思い浮かびます。コンストラクターからパラメーターを完全に取り出し、インターフェイスの上のクラスを構成する型を作成し、必要に応じて適切な具象型を挿入します。

フーインターフェース

interface Foo {
  public void setBar(Bar bar);
  public Bar getBar();
}

バー インターフェイス

interface Bar {
  public void setFoo(Foo foo);
  public Foo getFoo();
}

Guiceなどを使用して、物事をさらに分離し、自動的にインジェクションを行うことを検討してきました。

于 2013-06-17T01:17:58.760 に答える
1

あなたの質問は、循環参照に関する簡単な質問です。

まず第一に、ここに記載されている多くの理由から、循環参照を避けるようにクラスを設計する必要があります

次に、選択肢がない場合の最善の解決策は、「依存性注入」を使用することです。なんで?次のように考えてください。

  1. Foo オブジェクトを作成する必要があります
  2. foo を作成するときに、Bar も作成する必要があります
  3. ただし、明らかな理由から、Bar インスタンスをハードコーディングしたくはありません。
  4. あなたが言及した理由により、コンストラクターで「オーバーライド可能な」メソッドを呼び出すことは問題があります

したがって、依存性注入は安全な救助になります。

于 2013-06-17T01:36:29.053 に答える
0

選択肢の 1 つは、初期化用に別の関数を作成し、子クラス ctor で init メソッドを呼び出すことです。

例えば

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 を Foo に注入することを検討する必要があります。


コメントで、最終的な必要性について言及しました。

メンバー var が非公開になった場合など、non-final は大きな問題ではないと思いますが、初期化作業が単純な場合に検討できる別の方法 (実際には上記と同様) を次に示します。あなたの質問のように:

class Foo {
    protected final Bar child;

    public Foo() {
        this.child = new Bar(this);
    }
}

class Foo2 {
    public Foo2() {
        this.child = new Bar2(this);
    }
}

コードをテストしていませんが、動作するはずです:P

于 2013-06-17T01:36:00.867 に答える