結合された汎用境界はアンチパターンですか?
-
11-07-2019 - |
質問
私の前の質問のフォローアップとして 次のような一般的な境界が組み合わされた関数を持っている
<T extends Foo & Bar> void doStuff(T argument) {
//do stuff wich should only be done if arguments is both foo and bar
}
これは不特定のオブジェクトからキャストできないため、これらのインターフェースを実際に実装するオブジェクトの知識が必要です。 doStuff(T a)
に渡すオブジェクト引数の特定のタイプを知る必要があることは、Demeterの法則に違反しているように思えます。
この関数は、実際のクラスを知る必要性を指定していません(多くの異なるクラスが存在する可能性があります)。このクラスを知っているとコードベースの依存関係が増加するため、本当に知りたくありません。
これらの境界を使用するのはアンチパターンですか?もしそうなら、どうすればそれを避けるべきでしょうか?
ケースシナリオでは、オブジェクトを指定する1つのインターフェイスが永続的で、他の指定されたオブジェクトに関連するエンティティが含まれます。この場合の doStuff(T a)
関数は、関連するエンティティが永続化されたときに永続化しました。ただし、非永続エンティティは関連エンティティを持つこともできますが、 doStuff(T a)
関数
正しい解決策はありません
他のヒント
一般的な境界の組み合わせをアンチパターンとは考えません。少なくとも、私のコードではそれらのいくつかの用途があります。たとえば、次のサンプルコードは、ComparableインターフェイスのcompareToを使用して、コレクション内の最大のNumberインスタンスを検索します。
<T extends Number & Comparable<T>> T max(Collection<T> numbers)
doStuff(T a)に渡すオブジェクト引数の特定のタイプを知る必要があることは、デメテルの法則に違反しているように思えます
同意しません。方法がわかりません
T<? extends Foo & Bar> void doStuff(T argument)
渡すためには引数の知識が必要です
T<? extends Foo> void doStuff(T argument)
またはさらにもっと
void doStuff(T argument)
すべての場合において、引数について何かを知る必要があります。最初のケースは2つの識別子を持っているので、他の場合よりも多くの知識を要求しているとは思いません。
アンチパターンがキャストされています。
ただし、高度なジェネリックフットワークは、経験のないプログラマーにとって混乱を招く可能性があります。そのようなタイプとメソッドの使用は、それらの実装よりもはるかに簡単なはずです。