「プリミティブオブセッション」を許可する正当な理由は「ヨーヨー問題を回避することですか?」 によると、「価格」を次のように定義する必要があります。
public class Main{
private Price price;
}
public class Price{
private double priceValue;
public static void roundToValidValue(double priceValue){
}
}
の代わりに
public class Main{
private double price;
}
public class PriceHelper{
public static double roundToValidValue(double priceValue){
}
}
保守性を高めるために、Priceに関するロジックをクラスにカプセル化する必要があるためです。しかし、「できるだけ抽象的な型を使用する」という目標に反しているように見えました( 実装(HashMap)ではなく、インターフェース(例:Map)を使用してJavaオブジェクトを定義する理由) ):
私が理解しているように、「できるだけ抽象的な型をできるだけ使用する」ことの目標の1つは、クラス間の結合を減らすことです。これにより、クライアントは呼び出さないメソッドの使用を回避できるため、クライアントはメソッドに依存しません。彼らが使用しないこと。ただし、Priceクラスに戻ると、「roundToValidValue」をまったく呼び出さないクライアントがあることがわかりました。 「プリミティブな強迫観念を回避する」ルールに従い、「roundToValidValue」を新しいクラスにカプセル化すると、「roundToValidValue」をまったく呼び出さないクライアントも「roundToValidValue」に依存し、「デカップリング」の目的に反するように見えます。 「可能な限り最も抽象的なタイプを使用する」で示唆されている。
また、 すべてのタイプを定義する必要がありますか? に従って、プリミティブタイプを使用してビジネスモデルを直接表すことは避けます。つまり、
public class Car{
private double price;
private double weight;
public void methodForPrice(double price){
}
}
に
public class Class{
private Price price;
private Weight weight;
public void methodForPrice(Price price){
}
}
これにより、間違ったメソッド、つまり:methodForPrice(weight)を呼び出す状況を回避できます。ただし、- 実装(HashMap)ではなくインターフェイス(たとえば、マップ)を使用してJavaオブジェクトを定義する理由 によると、可能な限り最も抽象的な型を使用することが推奨されます。
public LinkedHashMap<String,Stock> availableStocks;
public HashMap<String,Stock> unusedStocks;
public class Main{
public void removeUnusedStocks(Map<String,Stock> unusedStocks){
}
}
「原始的な強迫観念」の問題に苦しんでいる可能性があることに気づきました。「removeUnusedStocks(availableStocks)」を誤って呼び出すことがあります。より具体的なタイプを使用すると思います:
public class Main{
public void removeUnusedStocks(LinkedHashMap<String,Stock> unusedStocks){
}
}
両方のバージョンがひどく機能する場合でも優れているため、「できるだけ抽象的なタイプを使用する」ことは「原始的な執着を避ける」という目標に反すると思います。
その結果、「プリミティブオブセッションを回避する」と「できるだけ抽象的なタイプをできるだけ使用する」という目標は相反するものであり、「プリミティブオブセッションを回避する」と「できるだけ抽象的なタイプをできるだけ使用する」という目標は互いに矛盾していると思います。 ?
あなたの例で理解すべき重要な部分は、Price
すべきではないdouble
--と同じです。まず、double
s金額を正しく表すことができません。ただし、Price
には他の制限があります-マイナスにすることはできません。小数点以下3桁(USの場合)を超えることはできません。これらはtype invariantsです。タイプレベルで条件を適用することで、ミスを防ぎます。 Weight
についても同様です。これらを一緒に使用すると、Price
をWeight
に追加できなくなります-これは良いことです。
これらの理由により、double
はPrice
またはWeight
を抽象化したものではありません。それらは異なる目的を持つ完全に異なるタイプです。 Price
は、Weight
と同じように使用することはできません。つまり、double
を使用することはできません(使用する型であっても)内部で値を保存します)。抽象化は、具象型と同じ重要な不変式を保持する必要があります。 HashMaps
はMaps
であり、Map
を使用できる任意の方法で使用できます。
double
は抽象型ではないことに注意してください。それは具体的なものです。 Price
も抽象型ではありません。
すべてのスカラー型を抽象化するAbstractScalarType
がある場合でも、AbstractScalarType
はメソッドroundToValidValue
を指定できます(ただし、必ずしも実装する必要はありません)。そうは言っても、アプリケーションのそのようなクラスにはおそらくほとんど価値がありません。意味のない抽象クラスを発明しないでください。それらから継承できるからです。
最も抽象的な型を使用するという原則は、メソッドが受け入れる型を主に指します。物事のリストを分析してリストの内容の概要を生成するメソッドがある場合、そのメソッドが特定の種類のリスト(たとえば、単一リンクのソートされたリスト)でのみ機能することを指定する理由はありません。 anyリストの種類を受け入れる必要があります。
「ほとんどの抽象型を使用する」というルールの作成者は、おそらく単一フィールドクラスをそのコンテンツで置き換えることを意味していませんでした。結局のところ、double
はPrice
のスーパータイプではありません。むしろinterface Price
これは、異なるPriceImpl
クラスで実装できます。ここで使用することが正当化されるのであれば、別の質問です(私の意見ではそうではありません)。
"definethe Java実装ではなくインターフェース "は、
宣言時に最も抽象的な型を使用し、作成時に最も特殊な型を使用します
したがって、できるだけ抽象的な型を使用すると言うと、宣言時にを忘れます。主なアイデアは
その場合、removeStocks(Map<String,Stock> stocks)
は、未使用の在庫の削除(店舗での在庫など)と使用可能な在庫の削除(カートからなど)の両方に使用できます。タイプセーフは多くのエラーを防ぐことができますが、すべてではないことに注意してください。store.removeStocks(available)
は論理的なバグです。その理由でのみavailableStocks
をLinkedHashMap
として宣言すると、大きなエラー(パフォーマンスと保守性の両方)になります。
一方、それは重要な部分です可能な限り。重みには制限があるため、プリミティブdouble
を使用するのは不可能です。 LinkedHashMap<> availableStocks
をHashMap<> availableStocks
に変更しても何も変化しないため、より一般的なMap
を使用することをお勧めします
TL; DRそれらが矛盾する場合は、おそらくそれらの1つを間違った方法で使用しています。レビューの時間です。