web-dev-qa-db-ja.com

匿名vs名前付き内部クラス? - ベストプラクティス?

折れ線グラフをレンダリングするクラスをLineGraphと呼びます。サブクラス化する必要がありますが、派生クラスは1つの場所でのみ使用され、それを使用するクラスに結合されます。だから私は内部クラスを使用しています。

これには2つの方法があります。

匿名の内部クラス

public class Gui {
    LineGraph graph = new LineGraph() {
        // extra functionality here.
    };
}

名前付き内部クラス

public class Gui {
    MyLineGraph graph = new MyLineGraph();

    private class MyLineGraph extends LineGraph {
        // extra functionality here.
    }
}

私は匿名の内部クラスのファンではありません。率直に言って、本当に醜く見えるからです。しかし、1つの場所でのみ使用されるサブクラスの場合、名前付きの内部クラスはやりすぎですか?受け入れられている慣行は何ですか?

44
Joe Attardi

匿名内部クラスの利点の1つは、名前付き内部クラスを使用できるのに対し、誰もそれを他の場所で使用できないことです(プライベートにした場合にそれを作成したクラスによってのみ)。これは小さな違いですが、内部クラスが誤って他の場所で使用されないように保護できることを意味します。

また、匿名の内部クラスを使用すると、コードを読んでいる人は誰でもすぐに頭に浮かぶことができます。名前付きの内部クラスが表示される場合、そのクラスの複数の場所で使用されていると思われるかもしれません。

それらは非常によく似ているので、どちらの点も画期的なものではありません。 1回限りの匿名の内部クラスを使用し、クラス内で複数回使用される場合は名前付き内部クラスを使用すると、わかりやすくなると思います。

49
Daniel Lew

(ダニエルルーへのカウンターポイント)

匿名内部クラスの1つの欠点は、名前付き内部クラスを使用できるのに対し、それを他の場所で使用できないことです(プライベートにした場合に、それを作成したクラスによってのみ)。これは小さな違いですが、内部クラスが誤って別の場所に再作成されないようにするのに役立つことを意味します。

また、匿名の内部クラスを使用すると、どこからともなく出てきたこのクラスを解析しなければならないため、コードを読む人は誰にとっても苦労します。名前付きの内部クラスを使用すると、ソースをさらに整理できます。

まったく同じコードを持つ2つ(またはそれ以上)の匿名内部クラスがあるケースを見てきました。特にGUI(同じアクションを実行する複数のコントロールがある場合)では、これが発生する可能性があります(そして、私は生徒が書いたコードではなく、製品コードを話している)。

可読性の問題は両方の方向に行きます。1か所で何が行われているのかを確認できるため、匿名の内部クラスをよりよく見つける人もいれば、気が散る人もいます。その部分は個人的な好みに帰着します。

また、クラスを静的にする方が効率的です。インスタンスで匿名の内部クラスを宣言している場合は、オーバーヘッドが増えるため、インスタンス変数にアクセスする必要がない場合は無駄になります(ただし、心配する価値はありません)。問題になるまで)。

私の個人的な好みは、非コードクラスを使用することです。非コードクラスを使用すると、後でコードを変更するときに柔軟性が高まります。

36
TofuBeer

なぜそれをサブクラス化する必要があるのですか?既存の仮想メソッドをオーバーライドするだけの場合は、匿名の内部クラスで問題ないと思います。機能を追加する場合は、名前付きクラスを使用します。私はそれをネストされたクラスにします(つまり、static修飾子を使用します)-私はそれらを推論するのが簡単だと思います:)

10
Jon Skeet

機能する可能性のある最も単純なことを行う :匿名の内部クラスを使用します。

後でより広い範囲が必要であることがわかった場合は、これをサポートするようにコードをリファクタリングします。

(変数についても同じことを行います。それらを最も具体的なスコープに入れます。他のソースアセットについても同じことを行うのは理にかなっています。)

8
Jeff Grigg

匿名の内部クラスは、Eclipseでデバッグするのが困難です(これを使用しています)。右クリックするだけでは、変数値/注入値を確認することはできません。

4
Kapsh

私の個人的な経験則:匿名の内部クラスが小さくなる場合は、匿名クラスを使用します。約20〜30行以下と定義されています。それが長くなると、私の考えでは読みにくくなるので、名前付きの内部クラスにします。 4000+行の匿名の内部クラスを見たことがあります。

3
Avrom

内部クラスの欠点は、静的にすることができないことです。これは、がそれらを含む外部クラスへの参照を保持することを意味します。

非静的内部クラスが問題になる可能性があります。たとえば、最近内部クラスがシリアル化されましたが、外部クラスはシリアル化できませんでした。非表示の参照は、外部クラスもシリアル化されることを意味しましたが、もちろん失敗しましたが、理由を見つけるのにしばらく時間がかかりました。

私が作業している場所では、静的な内部クラスは隠された手荷物が少なく、無駄が少ないため、コーディングのベストプラクティス(可能な場合)で推奨されています。

3
user15299

無名クラスは名前を持たないため、コンストラクターを持つことはできません。拡張するクラスのコンストラクター以外の変数を渡す必要がある場合は、(静的)名前付き内部クラスを使用する必要があります。これは、周囲のメソッド/コードで最終的な変数を使用することで克服できる場合がありますが、少し見苦しいです(そして、Robinが言ったことにつながる可能性があります)。

2
druidu

匿名の内部クラスが一般的な方法です。とても読みやすいと思います。ただし、そのクラスのインスタンスをシリアル化する必要がある場合(それが何か他のフィールドであるという理由だけである場合でも)、名前付き内部クラスを使用することを強くお勧めします。バイトコード内の匿名の内部クラスの名前は非常に簡単に変更される可能性があり、これによりシリアル化が中断される可能性があります。

2
Adam Crume

匿名クラス:

  • 定義にstaticを含めることはできません(静的クラス、静的フィールド、静的初期化子など)
  • eclipseではフィールドを検査できません
  • タイプとして使用できません(Foo$1 myFoo=new Foo$1(){int x=0;}は機能しません)
  • eclipseでクラス名を使用して見つけることができません(_Foo$1_を検索しても機能しません)
  • 再利用できません

ただし、匿名クラスは{super.foo(finalVariable+this.bar);}のような初期化子を持つことができます

名前付き内部クラスにはこれらの制限はありませんが、長いプロシージャの途中で排他的に使用されている場合でも、宣言を次の名前付きクラスに移動する必要があります。

以下の理由で制限が適用されない場合、個人的には匿名の内部クラスを好みます。

  • 追加のフィールドはクラス定義でのみ参照されることを知っています。
  • Eclipseはそれらをネストされたクラスに簡単に変換できます。
  • 使用したい変数をコピーする必要はありません。私はそれらを最終的に宣言して参照することができます。これは、パラメータが多い場合に特に便利です。
  • 相互作用するコードは互いに接近しています。
1
yingted

単純な匿名クラスには問題はありません。ただし、コードが数行以上または2つ以上のメソッドで構成されている場合は、内部クラスの方が明確です。また、特定の条件下では使用しないでください。データを返さなければならない場合など。

1項目の最後の配列を使用して、呼び出しから匿名の内部クラスにデータを返すコードを見てきました。 anonクラスのメソッド内で、単一の要素が設定され、メソッドが完了すると、この「結果」が抽出されます。有効ですが見苦しいコードです。

1
Robin

今日、私の同僚とこの議論をして、世論を求めて掘り下げていました。

私は豆腐ビールに同意します。コードに3行以上ある場合、おそらく「1回限り」ではなく、いつか再利用される可能性があります。 MVCパターンを使用してフォームを作成している場合、大量の匿名クラスでビューを乱雑にする代わりに、ページ上に20の制御可能な要素がある可能性があります(おそらく、ビューはGUIビルダーを使用して作成され、コードは自動生成されていましたオプションではなくソースを編集する場合)各要素をコントローラーにフィードする可能性があります。コントローラー内に内部クラスをネストして、ビューに必要なさまざまなハンドラー/リスナーインターフェイスを処理できます。これにより、特にハンドラークラスにGUI要素名(backButtonElementのbackButtonHandlerなど)を使用して名前を付ける必要があるという慣習がある場合は、コードが適切に編成されます。これは非常にうまく機能し、自動登録ツールを作成しました(ビューにコントローラーを登録すると、ビューは要素名を使用して内部クラスを探し、名前付きの各要素のハンドラーにそれらを使用します)。これは匿名クラスでは不可能であり、コントローラーをはるかにリサイクル可能にします。

TLDR:疑わしい場合は、名前付きの内部クラスを記述します。誰かがいつかコードを再利用したいのかどうかは決してわかりません(2行でない限り、「このコードは匂いがしますか?」)うまく編成されたコードは、特にプロジェクトがメンテナンス中の場合、長期的にははるかに大きなメリットがあります。

0
dolbysurnd

この場合、あなたがやったことは完全に理にかなっていると思います。どちらにしても、この特定の問題で髪を本当に分割していると思います。どちらも非常に似ており、どちらでも機能します。

0
Mike Pone

匿名の内部クラスでは、含めるクラスメンバーの状態を変更できません。それらは最終版として宣言する必要があります。

0

これは好みの問題だと思います。私は Functors に匿名クラスを使用することを好みます。しかし、あなたの場合、内部クラスを使用します。これは、数行のコードだけではなく、おそらくメソッドだけではないので、パックすることになると思います。また、メソッドのどこかに隠されるのではなく、クラス内に配置することにより、スーパークラスに機能を追加するという事実を強調します。さらに、誰かが知っているかもしれませんが、いつか他の場所でサブクラスが必要になるかもしれません。もちろん、これはあなたのソフトウェアがどのように進化するかについてあなたがどれだけ知っているかに依存します。それ以外は、コインを投げるだけです。 :)

0
Andrei Vajna II