デザインのにおい:デフォルトコンストラクター

これは、 カプセル化とも呼ばれるポカヨークデザインに関するシリーズの5番目の投稿です。



デフォルトのコンストラクターは、コード内の「におい」です。 そうです。 それはとんでもないように聞こえるかもしれません ただし、次の点を考慮してください。オブジェクト指向は、一貫したコード(クラス) 動作とデータの カプセル化です 。 カプセル化とは、クラスがカプセル化するデータの整合性を保護する必要があることを意味します。 データが必要な場合は、コンストラクターを介して要求する必要があります。 対照的に、デフォルトのコンストラクターは、外部データは不要であると言います。 これは、クラス不変条件に関するかなり弱いステートメントです。

この投稿では「 匂い 」について説明していることに注意してください。 これは、特定のイディオムまたはパターン(この場合は既定のコンストラクター)がコードで見つかった場合、これが追加の調査をトリガーすることを意味します。

さらに注意するように、すべてがデフォルトコンストラクターで正常な場合、いくつかのシナリオがあるため、この投稿の目標はデフォルトコンストラクターを無効にすることではありません。 目標は、思考の糧を提供することです。


私の本を読むと静的な依存関係を示し、クラスの整合性を保護し、これらの依存関係の初期化されたコンシューマーが常に一貫した状態であることを保証するため、コンストラクターへの注入がまさにDIパターンの支配的なものであることを既に知っています。 これは、 コンパイラーが高速フィードバックを提供することによりこの関係を強化するため、フェイルセーフ設計です。

この原則は、DIをはるかに超えています。 以前の投稿で、引数を持つコンストラクターが必要な引数を静的に展開する方法を説明しました。

public class Fragrance : IFragrance { private readonly string name; public Fragrance(string name) { if (name == null) { throw new ArgumentNullException("name"); } this.name = name; } public string Spread() { return this.name; } }
      
      





Fragranceクラスは、コンストラクターを介して名前を要求することにより、名前の整合性を保護します。 クラスは独自の動作を実装するために名前を必要とするため、コンストラクターを介して要求することをお勧めします。 デフォルトのコンストラクターは、 一時的な接続を導入するため、フォールトトレラントではありません。

オブジェクトは動作とデータのコンテナでなければならないことに注意してください。 オブジェクトにはデータが含まれていますが、カプセル化する必要があります。 この場合(非常に一般的)、意味のあるデフォルト値を決定できない場合、コンストラクターを介してデータをオブジェクトに渡す必要があります。 したがって、デフォルトのコンストラクタの存在は、カプセル化違反を示している可能性があります。



デフォルトのコンストラクタの使用はいつ正当化されますか?

デフォルトのコンストラクターの使用が正当化されるシナリオがあります(以下のシナリオよりも多くのそのようなシナリオがあると確信しています)。



インターフェイスを実装して純粋な動作を表すクラスは、必ずしも悪いことではありません。 この設計は非常に強力です。

結論として、デフォルトのコンストラクタの存在は、問題のクラスの不変式を停止して考えるためのシグナルである必要があります。 デフォルトのコンストラクターは、カプセル化されたデータの整合性を保証しますか? 「はい」の場合、デフォルトのコンストラクターが適切であり、そうでない場合は適切ではありません。 私の経験では、デフォルトのコンストラクターはルールではなく例外です。



All Articles