Javaのインスタンスの置き換え?


10

したがって、私は現実の世界(学術プロジェクト以外)でのプログラミングにかなり慣れていinstanceofないため、特定のオブジェクトがどのクラスであるかを判断するために使用することは悪いことだと多くの投稿に出くわしました。

私の状況では、3つのクラスがあります。1つは基本製品クラスで、もう1つはそれを拡張し、もう1つはそれを拡張します。これらはすべてデータベースの同じテーブルに格納されており、データを取得するためにそれぞれのメソッドを使用する必要があるコードがいくつかあります。

この方法で回避するためのベストプラクティスは何ですか?ポリモーフィズムについていくつか読んだことがありますが、私が抱えている問題を解決する例は見つかりません。通常、これらはすべて、異なるオブジェクトから異なるものをプルする必要があるため機能しないメソッドをオーバーライドします。

これを行うためのより良い方法はありinstanceofますか、それともオブジェクトに固有のフィールドを取得するための使用または何らかの反射で立ち往生していますか?


10
キーワードinstanceofが間違っているということではありません。通常、オブジェクトのクラスを見つけようとすることが問題です。常に間違っているとは限りませんが、おそらくあなたの場合は間違っています。多分あなたが達成しようとしていることを私たちに教えてくれれば、多態性を使った解決策を提案できます。
Andres F.

2
さて、各クラスには固有のデータがあります。これらから特定のデータを引き出したい。私はこれまでに手伝ってくれた答えを理解したと思います。呼び出されるメソッドのようなもので、getSpecifics()それぞれに異なる方法で実装され、それぞれがクラスに固有のデータを返すのですか?
Thomas Mitchell

回答:


16

その理由instanceofは、それがOOPではないからです。

オブジェクトの呼び出し側/ユーザーが、それがどの具象クラスのインスタンスであるかを、どのタイプの変数として宣言されているかを超えて知る必要はありません。

サブクラスで異なる動作が必要な場合は、メソッドを追加して、それらを異なる方法で実装します。


1
したがって、getSpecifics()各クラスの詳細を返す各クラスのメソッド(または類似のもの)です。これは最善の方法ですか?
トーマスミッチェル

@Schmoooクラスツリー内のどこに共通の機能が存在し、各レベルにどのようなコントラクトが存在するかを本当に考える必要があります。

3
しかし、オブジェクトがレイヤーを越えて型情報が失われた場合はどうでしょうか?例を作成しListます。それを受け取るオブジェクトに渡しますIterable。2番目のオブジェクトが3番目のオブジェクトに渡すとList、最適化のために、またはを使用しIterableますが、速度が大幅に低下します。2番目はリストであることを知らないはずですが、3番目は非常に知りたいと思っています。3番目のオブジェクトがinstanceofをチェックして、最適化を適用できるかどうかを確認しませんか?たとえばFluentIterable、まさにそれを行うグアバを見てください。
Laurent Bourgault-Roy 2013

1
クラスにメソッドを追加する必要があるとは限りません。たとえば、一部のコードは例外を受け取り、そのタイプに応じて何かを行うことになっています。たとえば、レポートを作成するか、エラーから回復するために何かをします。この種の機能は、例外に適していません。または、クラスが外部ライブラリからのものである場合、これらのクラスを変更する手段さえありません。この場合、に依存することは絶対に有効だと思いますinstanceof
マルコム

9

instanceof 必ずしも悪いことではありませんが、注意する必要があります。

正しく機能する例としては、基本タイプのコレクションを取得し、サブタイプのコレクションのみが必要な場合があります。からネットワークアドレスを取得するとNetworkInterface.getNetworkInterfaces()、InetAddressオブジェクトのコレクションを含むNetworkInterfaceオブジェクトが返されます。Inet4Addressオブジェクトのコレクションをフィルタリングする場合は、instanceofを使用する必要があります。

元の投稿で説明されている状況では、Baseクラスがあり、その基本クラスを拡張するものと拡張クラスを拡張するものがあります。完全に有益ではありませんが、これは理想的ではない設計の基礎を持っているようです。

そのように設計された正当な理由がない限り(以前のバージョンの仕様間の下位互換性)を除き、基本クラスを返すときは、基礎となる型を調べようとすべきではありません。セットが返された場合は、セットを取得しています。これにより、開発者は後で気を変えて、より具体的なタイプ(SortedSet)を返すか、基になるタイプ(HashSetからTreeSet)を変更することができます。

オブジェクトの構造とペアレント化の方法の設計を再検討して、タイプの区別を必要としない、より優れたクラスモデルを作成できるかどうかを確認してください。


インターフェースでisOfType(SomeEnum.IPv4)メソッドを指定することは、を介して具象タイプを検査するよりも、そのような品質をフィルタリングするためのより良い方法である可能性がありますinstanceof。IPv4実装クラスを後で分割したい場合はどうなりますか?これは常に良いというわけではありませんが、考慮事項です。
Steven Schlansker、2013年

@StevenSchlanskerその特定のクラスでうまくいくかもしれません。しかし、キャストが可能かどうかを確認するために具象型を検査する必要がある場合(またはキャストして例外をキャッチするだけの場合)は、Inet6AddressはInetAddressよりも多くのメソッドを実装します。インターフェース(パッケージ内のすべてのクラスを列挙する列挙型?またはクラスローダー?)を操作するのは困難であり、メソッドを手動で実装する必要があることを意味します(またはObjectのリフレクションコード)。方法を検討してください(o instanceof Serializable) || (o instanceof Externalizable)。instanceofは代替より優れています

1

getClass()メソッドを使用できます。

3つの異なるクラスが必要ですか?内部にスイッチがある1つのクラスの方が良いでしょうか?


7
getClassinstanceof欠点を共有します。ポリモーフィズムは、適合する場合はどちらよりも優れており、OPのユースケースに適合しないとは思いません。

私はあなたの最初の文に対して何もしません。しかし、2つ目-申し訳ありませんが、どういう意味か理解できません。
Gangnus 2013年

1
getClass私はまだ使用して同じ問題を共有していませんかinstanceof?私はまだ自分が持っているものを見つけて、一連の関数を呼び出す必要があります。理想的には、そのオブジェクトにキャストする必要なく、そのクラスに固有のデータを返すメソッドが必要です。
Thomas Mitchell

ポリモーフィズムの方が良い選択であることが多いので、ポリモーフィズムを無視することについて不満を述べています。問題のユースケースはポリモーフィズムで実行できると確信しているため、どちらも使用する必要はないと思います。(それを除けば、他人の答えを

2
@Gangus私はこれを「攻撃」とは考えていません。しかし、何でも。いいえ、問題は「他に何が使用できるか」ではなく、「これを行うためのより良い方法があるか」です。あなたgetClassがそれを行うためのより良い方法であると主張したくない限り、それは答えのほとんどを占めるビジネスはありません;-)

1

通常、何かのタイプを知りたいと思ったときは、オブジェクト構造を間違って実装したことを意味します。これらの時間のほとんどは、LSP違反に帰着します。

ただし、動的ディスパッチを実行して大量のボイラープレートコードを保存し、オブジェクト構造の将来性を保証する方法が欲しい場合があります。C#は、フレームワークの新しい記事に動的キーワードを提供しますが、私の知る限り、Javaにはまだ同様のものがありません。

とは言っても、instanceofは継承を適切にサポートするため、クラスを比較するよりも一般的に優れています。isAssignableFromなどのメソッドを反射APIから使用することもできます。動的ディスパッチなどを実装したい場合は、リフレクションAPIを介して実行できますが、注意が必要です。注意して使用してください。可能であれば、オブジェクト構造とアプリのデザインを修正するのが理想的です。

お役に立てれば

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.