データオブジェクトに依存性注入を使用しますか?


11

私は依存関係の注入について学んでいるだけで、何かにこだわっています。依存性注入では、コンストラクターを介して依存クラスを送信することをお勧めしますが、これがデータオブジェクトに必要かどうかは疑問です。単体テストはDIの主な利点の1つであるため、データを格納するだけで、プロシージャを単体テストすることはなく、DIを不要な複雑なレイヤーにするデータオブジェクト、または依存関係の表示にも役立ちますデータオブジェクトで?

Class DO{
    DO(){
        DataObject2List = new List<DO2>();
    }

    public string Field1;
    public string Field2;
    public List<DO2> DataObject2List;
}

Class DO2{
    public DateTime Date;
    public double Value;
}

「データオブジェクト」とはどういう意味ですか?それは標準的な用語ではありません。DTOについて話しているのですか、それともメソッドを持たないクラス(ドメインモデルの特に退屈な部分など)のみを参照していますか?2つの間に大きな違いがあります。
アーロンノート

もちろん、メソッドを持たないクラス、つまりデータを保存するだけのクラスを意味します。データオブジェクトがこれの正しい用語ではない場合、それがありますか、それともメソッドのないクラスと呼ばれていますか?
-sooprise

@soopriseこれはいい質問です。いい考え。
マシューロダトゥス

@soopriseおそらく私の答えはベースから外れています。CRUDメソッドはどこに配置しますか?データオブジェクトを取得し、それらをデータベーステーブルに永続化する別のデータアクセスクラスで?すなわち、DataAccess.Create(<DataObject>)?
マシューロダトゥス

1
@Matthew、これはデータアクセスオブジェクトになります -それが実際にOPが話しているものである場合、それはまったく明確ではありません。とにかく、現代の実装はこのパターンから離れ、リポジトリや作業単位に依存する傾向があります。
アーロンノート

回答:


7

ここで使用している用語の一部、特に「依存性」と「依存性注入」の明確化を提案したいと思います。

依存:

「依存関係」は通常、別のクラスが依存する必要がある機能を実行する複雑なオブジェクトです。古典的な例には、ロガーやデータベースアクセサー、または特定のビジネスロジックを処理するコンポーネントがあります。

データのみ、彼らはいくつかの必要な機能を実行しないので、DTOまたは値オブジェクトなどのオブジェクトは、通常、「依存」と呼ばれていません。

あなたはそれをこの方法を見たら、あなたは(あなたの例では何をしているか構成DOのリストを持つオブジェクトD02のコンストラクタによるオブジェクト)は、全ての「dependecy注入」とみなされるべきではありません。プロパティを設定するだけです。コンストラクターで提供するか他の方法で提供するかはユーザー次第ですが、コンストラクターに渡すだけでは依存関係の注入は行われません。

依存性注入:

DO2クラスが実際にDOクラスに必要な追加機能を提供している場合、それは本当に依存関係になります。その場合、依存クラス、DOはインターフェイス(ILoggerやIDataAccessorなど)に依存し、呼び出し元のコードに依存してそのインターフェイスを提供する必要があります(言い換えると、DOインスタンスに「注入」します)。

このように依存関係を注入すると、DOオブジェクトがより柔軟になります。異なるコンテキストごとに、DOオブジェクトへのインターフェイスの独自の実装を提供できるためです。(ユニットテストを考えてください。)


7

質問の混乱を克服するために最善を尽くします。

まず、「データオブジェクト」は意味のある用語ではありません。このオブジェクトの唯一の特徴がメソッドを持たないことである場合、それはまったく存在すべきではありません。有用な動作のないオブジェクトは、次のサブカテゴリの少なくとも1つに収まる必要があります。

  • 値オブジェクトまたは「レコード」にはIDがまったくありません。それらは、環境がサポートしていると想定して、参照時コピーのセマンティクスを持つ値でなければなりません。これらは固定構造であるため、VOはプリミティブ型またはプリミティブの固定シーケンスのみである必要があります。したがって、VOには依存関係関連付けを設定しないでください。デフォルト以外のコンストラクタは、値を初期化するためだけに存在します。つまり、リテラルとして表現できないためです。

  • データ転送オブジェクトは、しばしば値オブジェクトと誤って混同されます。DTOに IDがありますが、少なくともそうすることができます。DTOの唯一の目的は、あるドメインから別のドメインへの情報の流れを促進することです。彼らは決して「依存関係」を持ちません。彼ら(つまり、配列またはコレクションへの)関連付けを持っているかもしれませんが、ほとんどの人はそれらをフラットにすることを好みます。基本的に、これらはデータベースクエリの出力の行に似ています。通常は永続化またはシリアル化する必要がある一時的なオブジェクトであり、したがって抽象型を参照することはできません

  • 最後に、データアクセスオブジェクトは、何らかの種類のデータベースにラッパーまたはファサードを提供します。これらには明らかに依存関係があります-データベース接続や永続化コンポーネントに依存します。ただし、それらの依存関係はほとんど常に外部で管理され、呼び出し元にはまったく見えません。Active Recordのパターンは設定を通して、すべてを管理フレームワークです。古い(今日の標準では古代の)DAOモデルでは、コンテナを介してしかこれらを構築できませんでした。これらのいずれかをコンストラクター注入で見た場合、私は非常に心配しています。

また、エンティティオブジェクトまたは「ビジネスオブジェクト」について考えることもできますが、この場合は、依存関係の注入をサポートたいのですが、考えている方法や考えている理由ではありません。これは、の利益のためではありませんユーザーコード、それは静かに注入しますエンティティマネージャまたはORMの利益のためだ、プロキシ、クエリの理解や遅延ロードのような派手なものを行うためにインターセプトします。

これらでは、通常、インジェクションのコンストラクタを提供しません。代わりに、プロパティを仮想化し、抽象型を使用する必要があります(たとえばのIList<T>代わりにList<T>)。残りは舞台裏で行われ、誰も賢明ではありません。

全体として、「データオブジェクト」に適用される目に見えるDIパターンは不要であり、おそらく赤旗でさえあると言えます。しかし、大部分は、データベースのデータを表すために特に使用されている場合を除いて、オブジェクトの存在そのものが赤旗であるためです。他のほとんどの場合、それはコード臭であり、通常は貧血領域モデルの始まり、または少なくともポルターガイストです。

繰り返すには:

  1. 「データオブジェクト」を作成しないでください。
  2. 「データオブジェクト」を作成する必要がある場合は、明確に定義された目的があることを確認してください。その目的は、DIが適切かどうかを示します。そもそも存在してはならないオブジェクトについて、有意義な設計上の決定を下すことは不可能です。

フィン。


0

あなたの例でDOは、機能的な依存関係はありません(基本的に何もしないため)。具象型に依存しているため、DO2abstract DO2にインターフェースを導入して、コンシューマが子クラスの独自の具象実装を実装できるようにすることができます。

本当に、ここにどんな依存関係を注入しますか?


私が答えた彼の別の質問によると、この質問はCRUD操作が組み込まれたデータオブジェクトに関するものだと思います。データベースの依存関係はどのように/どこにデータオブジェクトに注入されますか?メソッドで?コンストラクターで?他の方法は?前提は、依存関係がメソッドの本体に隠されてはならないことです。これにより、データオブジェクトを単体テストできるように、データオブジェクトからデータベースの依存関係を分離できなくなります。
マシューロダトゥス

@Matthew Rodatus-なるほど。はい、その場合、2つの選択肢があります。永続化サービスを注入するDOPersisterか、永続化する方法を知っている別のクラスを作成DOし、厳密にデータのみのオブジェクトとして残します(私の意見ではより良い)。後者の場合、DOPersisterデータベースの依存関係が注入されます。
スコットホイットロック

彼の質問を読み直した後、私はよくわかりません。私の分析は間違っているかもしれません。彼は彼の質問で彼のDOには手続きがないと言った。これは、DOで永続性が発生しないことを意味します。その場合、あなたの答えは正しいです。注入する依存関係はありません。
マシューロダトゥス

0

これはデータアクセス層のデータオブジェクトなので、データベースサービスに直接依存する必要があります。DatabaseServiceをコンストラクターに指定できます。

DataObject dataObject = new DataObject(new DatabaseService());
dataObject.Update();

ただし、インジェクションはコンストラクタ内にある必要はありません。または、各CRUDメソッドを介して依存関係を提供できます。データオブジェクトは、実際に永続化する必要があるまで、どこに永続化するかを知る必要がないため、以前よりもこの方法を好んでいます。

DataObject dataObject = new DataObject();
dataObject.Update(new DatabaseService());

CRUDメソッドで構造を隠したくないことは間違いありません!

public void Update()
{
    // DON'T DO THIS!
    using (DatabaseService dbService = new DatabaseService())
    {
        ...
    }
}

別のオプションは、オーバーライド可能なクラスメソッドを介してDatabaseServiceを構築することです。

public void Update()
{
    // GetDatabaseService() is protected virtual, so in unit testing
    // you can subclass the Data Object and return your own
    // MockDatabaseService.
    using (DatabaseService dbService = GetDatabaseService())
    {
        ...
    }
}

最後の選択肢は、シングルトンスタイルのServiceLocatorを使用することです。私はこのオプションが嫌いですが、単体テスト可能です。

public void Update()
{
    // The ServiceLocator would not be a real singleton. It would have a setter
    // property so that unit tests can swap it out with a mock implementation
    // for unit tests.
    using (DatabaseService dbService = ServiceLocator.GetDatabaseService())
    {
        ...
    }
}
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.