IoCコンテナを使用してエンティティ/ビジネスオブジェクトの依存関係を解決してみませんか?


82

DIの背後にある概念は理解していますが、さまざまなIoCコンテナーで何ができるかを学んでいます。ほとんどの人がステートレスサービスを接続するためにIoCコンテナーを使用することを提唱しているようですが、エンティティなどのステートフルオブジェクトにそれらを使用するのはどうでしょうか。

それが正しいか間違っているかにかかわらず、私は通常、その動作に外部クラスが必要な場合でも、エンティティに動作を詰め込みます。例:

public class Order : IOrder
{

    private string _ShipAddress;
    private IShipQuoter _ShipQuoter;

    public Order(IOrderData OrderData, IShipQuoter ShipQuoter)
    {
        // OrderData comes from a repository and has the data needed 
        // to construct order
        _ShipAddress = OrderData.ShipAddress;  // etc.
        _ShipQuoter = ShipQuoter;

    }

    private decimal GetShippingRate()
    {
        return _ShipQuoter.GetRate(this);
    }
}

ご覧のとおり、依存関係はコンストラクター注入です。さて、いくつか質問があります。

  1. エンティティをShipQuoterなどの外部クラスに依存させることは悪い習慣と見なされますか?定義を正しく理解していれば、これらの依存関係を排除することで、貧血の領域に向かうように思われます。

  2. IoCコンテナを使用してこれらの依存関係を解決し、必要に応じてエンティティを構築することは悪い習慣ですか?これを行うことは可能ですか?

洞察力をありがとう。


3
仕事が楽になるので、必要なことをするだけです。おそらくこれがあなたのやり方だからではありません
Omu 2011年

28
独学のプログラマーとして、私はその道を進み、それが現在私の会社で使用されているソフトウェアにつながりました。手続き型/トランザクションスクリプトベースのソフトウェアが登場したのは、それが最も簡単で、私がよく知らなかったためにパーティーだったためです。維持・拡大するのは大変なことですので、時間をかけて書き直し、同じ過ちを犯さないように、すでにこれらの問題を克服している方にアドバイスを求めています。
ケーシーウィルキンス

回答:


90

最初の質問は答えるのが最も難しいです。エンティティを外部のクラスに依存させるのは悪い習慣ですか?それは確かに最も一般的なことではありません。

たとえば、リポジトリをエンティティに挿入すると、アクティブレコードパターンが効果的に実装されます。このパターンが提供する利便性のために好む人もいれば、(私のように)単一責任原則(SRP)に違反しているため、コードの臭いやアンチパターンだと考える人もいます。

他の依存関係をエンティティに注入すると、同じ方向に(SRPから離れて)引っ張られると主張することができます。一方、これを行わない場合、プルは貧血ドメインモデルに向かうということは確かに正しいです。

DDDDに関するGregYoungの(放棄された)論文に出くわすまで、私はこれらすべてに長い間苦労しました。そこで彼は、ステレオタイプのn層/ n層アーキテクチャが常にCRUDy(したがってむしろ貧血)になる理由を説明します。

ドメインオブジェクトを名詞ではなくコマンドとイベントとしてモデル化することに焦点を移すと、適切なオブジェクト指向ドメインモデルを構築できるようになります。

2番目の質問は答えるのが簡単です。いつでもAbstractFactoryを使用して、実行時にインスタンスを作成できます。Castle Windsorを使用すると、Typed Factory Facilityを使用することもでき、工場を手動で実装する負担が軽減されます。


マークに感謝します。Typed Factoryを見たり、Abstract Factoryメソッドに関する他の投稿を読んだりしましたが、エンティティの解決に使用されている例は見たことがありません。これは、ほとんどの人がリポジトリ以外の依存関係なしでエンティティを設計しているためですか?Typed Factoryのようなものを厳密に使用して、外部の依存関係を持つエンティティを解決すると、将来的に問題が発生しますか?
ケーシーウィルキンス

私が言おうとしていたのは、エンティティに他のエンティティなどにアクセスする可能性のある他の共同作業者が含まれている場合、SRP違反やN + 1の問題は言うまでもなく、あらゆる種類のメンテナンスの問題が発生する可能性があるということです。そのため、Evansは各エンティティを集約ルートとして扱うことを推奨しています。
マークシーマン2011年

私の例では、ShipQuoterはWebサービス(UPSなど)から注文の配送料を引き出します。これをIOrderを受け入れるサービスにしますか、それともOrder.GetRatesのようなドメインオブジェクトの一部にしますか?
ケーシーウィルキンス

そもそも同期プルを回避する方法を見つけるのに多くの時間を費やしました。同期してブロックする方法でデータをプルするほど、デザインはより脆弱になります。そのため、CQRSは非常に魅力的な代替手段です。
マークシーマン2011年

4
グレッグの論文へのあなたのリンクは死んでいます。しかし、それはまだここで利用可能です。そして、これは新しいバージョンのようです。
BornToCode 2016年

1

これは古い投稿ですが、追加したいと思います。ctorで抽象化されたリポジトリを渡しても、ドメインエンティティはそれ自体を永続化しないでください。私が提案している理由は、これがSRPに違反しているだけでなく、DDDの集計にも反しているということです。説明させてください。DDDは本質的に深いグラフを持つ複雑なアプリに適しているため、集約ルートまたは複合ルートを使用して、基になる「子」への変更を永続化します。したがって、個々の子に永続性を注入すると、子との関係に違反します。ライフサイクルまたは集約を「担当」する必要がある複合ルートまたは集約ルート。もちろん、複合ルートまたは集約は、それ自体のグラフも永続化しません。もう1つは、DDDオブジェクトの依存性を注入することです。注入されたドメインオブジェクトは、状態を調整するために他のイベントが発生するまで、事実上状態がありません。コードのコンシューマーは、カプセル化に違反するビジネス動作を呼び出す前に、最初にドメインオブジェクトを初期化またはセットアップする必要があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.