特定のエンコーディングなど、構造化された方法でユニット情報を取得するメソッドを備えたユニット情報のコレクションを表すクラスUnitInfo
があります。このユニット情報は、ユニットから読み取る必要のある情報で構成されています。シリアルポート通信経由。クラスのコンストラクターには、ユニットから照会できないシリアル番号と、ユニットに情報を照会するために使用するインスタンスシリアル通信インターフェイスが与えられます。
public class UnitInfo {
public int SerialNumber { get; }
public int InternalMemorySize { get; }
// And more properties...
public UnitInfo(ISerialCom serialCom, int serialNumber) {
SerialNumber = serialNumber;
InternalMemorySize = serialCom.GetInternalMemorySize();
// More serial communication to set more properties
}
// Get methods to retrieve all the unit information in a specific encoding
// i.e a collection of bytes.
}
私のブラウジングSOとGoogleから、コンストラクタで作業を行うことは通常は問題ないことを理解していますが、シリアル、GPIBなどを介して通信を実行する例はまだ見つかりません。コンストラクタ。クラスはそれ自体を初期化するためにインターフェイスの実装に依存しているため、これは依存性注入の原則に違反している可能性があると考えています。すべてのユニット情報をクラスに渡す方がよいでしょうか。
このデザインは完全に素晴らしいです。外部ポートと通信していますが、おそらくコンピュータに直接接続されているハードウェアであるため、通信は迅速に行われます。
C#で作業しているので、ユーザーがプラグを(文字通り)プルした結果としてのコンストラクターの例外は問題になりません。共通言語ランタイムがクリーンアップを担当するためですが、ISerialCom
オブジェクトは、接続を管理する必要がある場合にIDisposable
を実装します(ただし、これはこのコンストラクターの責任ではありません)。
この重要な情報を提供するオブジェクトを受け入れることの良いところは、このオブジェクトの構築が非常に防弾になることです。シリアル番号の代わりに誤って内部メモリサイズを渡すことはできません。
これは、最終的には意見の問題であるものの1つです。あなたの現在受け入れられている答えはone意見ですが、それは私が共有するものではありません、そして 私はそれだけではありません :
コラボレーターの作成/初期化、他のサービスとの通信、独自の状態を設定するロジックなどのコンストラクターで作業し、テストに必要な継ぎ目を削除し、強制します不要な動作を継承するサブクラス/モック。コンストラクターでの作業が多すぎると、テストでのインスタンス化や共同作業者の変更が妨げられます。
(エンファシスマイン)
しかし、「フィールドの割り当て以上のもの」を警告サインと見なしているMisko Hevery(異なる意見...)にも100%同意することはできません。 nullチェックやintが特定の範囲内にあると主張するなどの「短くて甘い」検証は許容されます。
これについての私のお気に入りの比喩:歯科医の仕事は、歯科医院を建設することではありません。
それらのUnitInfoFactory
sの作成を担当するUnitInfo
を作成することはそれほど難しくないはずです。 UnitInfo
が非常に小さい場合は、静的ファクトリメソッドも問題ありません。
instantlyUnitInfo
の実装を何らかの方法で取得する代わりに、2つのintでISerialCom
を作成できます(例で省略したコードを無視します)もちろん)。ユニットテストを行う場合、これはゴールドです。モックフレームワークを使用しても、そのモックを作成するのは追加の作業であるためです。ただし、単体テストを行っていない場合でも、テスト可能になるように記述されたコードは、他のコードよりもクリーンになる傾向があります。
ただし、ここでのこの部分は意見の問題ではありません。
また、クラスはそれ自体を初期化するためのインターフェイスの実装に依存しているため、これは依存性注入の原則に違反している可能性があると考えています。
サンプルコードに関する限り、GetInternalMemorySize()
に対して常にゼロを返すISerialCom
のモック実装を提供できますが、それでも機能します。そのため、クラスは「インターフェイスの一部の実装に依存」するのではなく、インターフェイス自体にのみ依存します。
誤解は、クラスが実際に機能するためにまだ(y)実装が必要であるという事実にあると思いますが、それはDIの原則の目的ではありません。 David Arnoがコメントですでに述べたように、コンストラクターでnew
を使用すると問題が発生します。
これについて私が見つけた最高のニーモニックは「new isglue」です:コードでnew
を使用するたびに、そのコードは結び付けられますその特定の実装まで。 new
コンストラクター内を繰り返し使用すると、特定の実装のチェーンが作成されます。また、クラスを構築せずにインスタンスを「持つ」ことはできないため、そのチェーンを分離することはできません。
しかし、あなたはそれをしていないようですので、それは問題ありません。