クラスが作成したときに依存関係インジェクションランタイム値も必要ですか?
-
29-09-2019 - |
質問
バリューオブジェクトとサービスオブジェクトにシステムを分割すると仮定します(「テストに導かれたオブジェクト指向ソフトウェアの成長」で示唆されているように。
値オブジェクトの1つが突然、メソッドを実装するためにサービスにアクセスする必要がある場合はどうなりますか?
素敵なシンプルな価値オブジェクトがあるとしましょう。それは不変であり、いくつかの情報を保持しており、それがそれについてです。このようなものを使用するとしましょう。
CreditCard card = new CreditCard("4111-1111-1111-1111", "07/10");
if (card.isValid())
{
// do stuff
}
else
{
// don't do stuff
}
ここまでは順調ですね。 isValid()
カード番号にチェックディジットアルゴリズムを実装し、true/falseを返します。
さて、現在の時刻に対して有効期限を検証することにより、システムを強化したいとしましょう。 Value Object/Service Object Paradimを壊さずにこれが行われることをどのように提案しますか?このクラスは、ユニットテスト可能であり続ける必要があります。
CreditCard
現在、依存関係がありますが、作成方法のために注入することはできないため、依存関係の注入が発生します。-
CreditCard
クラスはシングルトンに声をかけてはいけません(私はシングルトンへの世界的なアクセスが悪い練習であるという立場です) - 動作を装着します
CreditCardVerificationService.validateCard()
既存のすべてのコードを再検討する必要があることを意味します。 isValid()の実装が漏れています。
これを回避するためにできることがあることは知っていますが、最もクリーンな方法は何ですか?
解決
私は、何かを検証することはクレジットカードオブジェクトの仕事ではないと主張します。工場では、チェックディジットを検証して、適合カードをインスタンス化していることを確認しますが、検証サービスは有効期限/$制限のためにカードを検証します。
他のヒント
私はそれを言いたくなるでしょう CreditCard
値オブジェクトではありません。
から C2 wiki:
価値オブジェクトの例は、数字、日付、金銭、文字列などのものです。通常、それらは非常に広く使用されている小さなオブジェクトです。彼らのアイデンティティは、オブジェクトのアイデンティティではなく、状態に基づいています。これにより、同じ概念値オブジェクトの複数のコピーを使用できます。
値オブジェクトはBusinessObject/ReferenceObjectではありません。 BusinessObject/ReferenceObjectは世界で見つけたものですが、ValueObjectは何かの尺度または説明です。
もしも CreditCardNumber
バリューオブジェクトである可能性があります、 CreditCard
いくつかのビジネスロジック、例えば検証を含むビジネスオブジェクトのように見えます。
私は通常、バリューオブジェクト、サービス、およびビジネスオブジェクトを持っています。 「オブジェクト指向のソフトウェアの栽培」については知りませんが、オブジェクトのみに制限することとサービスのみを制限することは、私には奇妙に思えます。
電話します CreditCard
an 実在物 ではなく 値オブジェクト, 、それは永続的であり、ユニークなアイデンティティを持っている可能性が高いためです。
とにかく、エンティティクラスがサービスクラスを使用することは完全に問題ありません。外部構成に基づいて実行時に上記のサービスの実装を選択する必要がない場合は、クライアントメソッド内の目的のサービスクラスを単純にインスタンス化して使用します。一部の人が考えるかもしれないこととは反対に、これは単位テストを排除しません。モッキングツールは分離に使用できるからです。
サービスの実装の場合 します 実行時に選択する必要があります サービスロケーター 使用することができます。このパターンは、特殊なモッキングツールを必要とせずに、モッキング/フェイクを直接サポートできます。 「新しい」オブジェクトへの注入をサポートするDIフレームワークの使用は、別の代替手段です。