私がよく遭遇する問題は次のとおりです。Productクラスを持つWebショッププロジェクトがあるとします。ユーザーが製品にレビューを投稿できる機能を追加したい。そのため、製品を参照するレビュークラスがあります。次に、製品に対するすべてのレビューをリストする方法が必要です。2つの可能性があります。
(A)
public class Product {
...
public Collection<Review> getReviews() {...}
}
(B)
public class Review {
...
static public Collection<Review> forProduct( Product product ) {...}
}
コードを見て、(A)を選択します:静的ではなく、パラメーターを必要としません。ただし、(A)は単一責任原則(SRP)およびオープンクローズド原則(OCP)に違反しているのに対し、(B)はそうではないと感じています。
(SRP)製品のレビューの収集方法を変更する場合、製品クラスを変更する必要があります。ただし、Productクラスを変更する理由は1つだけです。そして、それは確かにレビューではありません。Productの製品と関係のあるすべての機能をパックすると、すぐに散らかってしまいます。
(OCP)Productクラスを変更して、この機能で拡張する必要があります。これは原則の「変更のために閉鎖」部分に違反すると思います。レビューを実施するという顧客の要求を得る前に、私は製品が完成したと考え、それを「クローズ」しました。
より重要なことは、SOLID原則に従うか、よりシンプルなインターフェイスを使用するかです。
それとも私はここで何か間違ったことをしていますか?
結果
素晴らしい答えをありがとう 公式の回答として選ぶのは難しいです。
答えから主な議論を要約しましょう:
- pro(A):OCPは法律ではなく、コードの可読性も重要です。
- pro(A):エンティティの関係はナビゲート可能でなければなりません。両方のクラスがこの関係について知っている場合があります。
- pro(A)+(B):両方を行い、(A)から(B)に委任するため、製品が再び変更される可能性は低くなります。
- pro(C):finderメソッドを静的でない第3クラス(サービス)に配置します。
- コントラ(B):テストのモックを妨げます。
私の職場の大学が貢献したいくつかの追加事項:
- pro(B):ORMフレームワークは(B)のコードを自動的に生成できます。
- pro(A):ORMフレームワークの技術的な理由により、ファインダーの行き先とは無関係に、「閉じた」エンティティを変更する必要がある場合があります。とにかく、私は常に固執することができるとは限りません。
- コントラ(C):大騒ぎする;-)
結論
現在のプロジェクトでは、委任で(A)+(B)の両方を使用しています。ただし、サービス指向の環境では、(C)を使用します。
Assert(5 = Math.Abs(-5));
Abs()
は問題ではなく、それに依存するものをテストすることは問題です。依存するCode-Under-Test(CUT)を分離してモックを使用するための継ぎ目がありません。つまり、アトミックユニットとしてテストすることはできず、すべてのテストはユニットロジックをテストする統合テストになります。テストの失敗は、CUTまたはAbs()
(またはその依存コード)にある可能性があり、単体テストの診断上の利点がなくなります。