実装(HashMap)ではなくインターフェイス(Mapなど)を使用してJavaオブジェクトを定義する理由


17

ほとんどのJavaコードでは、次のようにJavaオブジェクトを宣言する人がいます。

Map<String, String> hashMap = new HashMap<>();
List<String> list = new ArrayList<>();

の代わりに:

HashMap<String, String> hashMap = new HashMap<>();
ArrayList<String> list = new ArrayList<>();

実際に使用される実装ではなく、インターフェースを使用してJavaオブジェクトを定義する設定があるのはなぜですか?


回答:


26

その理由は、これらのインターフェイスの実装は通常、それらを処理する際には関係がないため、呼び出し元にHashMapメソッドに渡すように義務付ける場合、使用する実装を本質的に義務付けるからです。したがって、一般的なルールとして、実際の実装ではなくインターフェースを処理し、代わりHashMapに使用する必要があると判断したときに使用するすべてのメソッドシグネチャを変更しなければならない痛みや苦痛を回避する必要がありますLinkedHashMap

実装が関連する場合、これには例外があると言う必要があります。順序が重要なときにマップが必要な場合は、a TreeMapまたはa LinkedHashMapを渡すことを要求SortedMapできます。特定の実装を指定していない場合は、さらに良いです。これにより、呼び出し側は必ずMapの特定のタイプの実装を渡す必要があり、順序重要であることを強く示唆します。とはいえSortedMap、ソートされていないものをオーバーライドして渡すことはできますか?はい、もちろん、結果として悪いことが起こることを期待しています。

ただし、ベストプラクティスでは、それが重要でない場合は、特定の実装を使用しないでください。これは一般的に真実です。あなたが扱っている場合DogCat、そこから派生Animal継承を最大限に利用するためには、あなたは一般的にメソッドの特定を避けるべきですDogCat。むしろすべてのメソッドで、DogまたはメソッドCatをオーバーライドする必要がAnimalあり、それは長い目で見ればトラブルを軽減します。


ソートされたマップが必要な場合、パラメータタイプはSortedMapでなくである必要がありTreeMapます。
頭足類14年

@Arian SortedMapは、順序付けを扱ういくつかの実装の1つです。それはポイントの外です。 TreeMapまた、キーの実装Comparableまたは指定されたComparatorインターフェイスに従ってアイテムを注文します。
ニール14年

いいえ、SortedMapは実装ではありません。まさにそれがポイントです。キーでソートするマップのインターフェースです。
頭足類14年

1
@Arian Ahおっしゃるとおりです。実装を強制しないため、SortedMapの方が優れています。適切な調整を行います。
ニール14年

実際、LinkedHashMapは実装されていませんSortedMap。唯一のサブクラスがSortedMapあるConcurrentSkipListMapTreeMap
bcorso 14

10

レイマンの言葉では:

電気機器メーカーが単にケーブルを剥がすのではなく電気プラグで製品を製造したのと同じ理由で、家には壁から突き出ているケーブルを剥がすのではなく、コンセントが付いています。

代わりに標準のプラグを使用することにより、家の周りの互換性のあるプラグに同じ器具を差し込むことができます。

壁のコンセントから見ると、テレビを接続するかステレオを接続するかは問題ではありません。

これにより、アプライアンスとソケットの両方がより便利になります。

引数としてMapを受け入れるメソッドを例にとります。

このメソッドは、Mapのサブクラスである限り、HashMapまたはLinkedHashMapを渡しても機能します。

それがリスコフの代替原理です。

サンプルコードでは、後で何らかの理由でハッシュの具体的な実装を変更でき、残りのコードを変更する必要がないことを意味します。

ソフトウェアの問題は、後でレンガやモルタルを無駄にせずに物事を変更するのが比較的簡単であるため、人々はその種の先入観はしばらくの間価値がないと仮定することです。しかし、現実には、ソフトウェアのメンテナンスが非常に高価であることがわかりました。


4

インターフェース分離の原則SOLIDの「I」)に従うことです。これらのオブジェクトを使用するコードが、必要のないオブジェクトのメソッドに依存することを防ぎます。これにより、コードの結合性が低下し、変更が容易になります。

たとえば、後で本当に必要な場合はLinkedHashMap、他のコードに影響を与えずに安全に変更できます。

ただし、オブジェクトをパラメーターとして使用できるコードを人為的に制限しているため、トレードオフがあります。何らかの理由でを必要とする関数がどこかにあるHashMapます。を返す場合Map、オブジェクトをその関数に渡すことはできません。将来的には、より具体的なクラスの追加機能が必要になる可能性と、結合を制限し、パブリックインターフェイスをできる限り小さくするという願望とのバランスを取る必要があります。


3

変数をインターフェイスに制限することにより、その変数の使用法がHashMapインターフェイスに存在しない可能性のある特定の機能を使用しないようにするため、新しいインスタンスも実装する限り、後で別の実装に関係なくインスタンスを変更できますインターフェース。

このため、オブジェクトインターフェイスを使用する場合は常に、特定の実装ではなくインターフェイスとして変数を宣言することをお勧めします。これは、インターフェイスを持つすべての種類のオブジェクトに適用されます。よく見る理由は、多くの人がこれを習慣として組み込んでいるからです。

それはそれは時々インタフェースを使用してのアウトスキップする有害ではない、と私たちのほとんどはだらしなくはありません、と述べ常に本当の害で、この規則に従ってください。コードが変更される可能性があり、将来的にメンテナンス/成長が必要になると感じた場合に固執するのは良い習慣です。寿命が長くなったり、重要性が高いと思わないコードをハッキングしている場合は、それほど心配する必要はありません。また、このルールを破ると、通常、実装を別のものに変更するには少しリファクタリングが必要になる可能性があるという小さな結果があります。 。

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