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);
}
}
보시다시피 종속성은 Constructor Injected입니다. 이제 몇 가지 질문입니다.
-
엔티티가 ShipQuoter와 같은 외부 클래스에 의존하도록하는 것이 나쁜 습관으로 간주됩니까? 이러한 종속성을 제거하면 정의를 올바르게 이해하면 빈혈 영역으로 연결되는 것 같습니다.
-
IoC 컨테이너를 사용하여 이러한 종속성을 해결하고 필요할 때 엔터티를 구성하는 것이 나쁜 습관입니까? 이것이 가능합니까?
통찰력을 가져 주셔서 감사합니다.
답변
첫 번째 질문은 대답하기 가장 어렵습니다. 엔티티가 외부 클래스에 의존하도록하는 것은 나쁜 습관입니까? 확실히 가장 흔한 일은 아닙니다.
예를 들어, 리포지토리를 엔터티에 삽입하면 효과적으로 액티브 레코드 패턴을 구현 한 것입니다 . 어떤 사람들은이 패턴이 제공하는 편의를 위해이 패턴을 좋아하는 반면 다른 사람들 (나와 같은)은 SRP ( Single Responsibility Principle)를 위반하기 때문에 코드 냄새 또는 안티 패턴으로 간주합니다 .
엔터티에 다른 종속성을 주입하면 동일한 방향 (SRP에서 멀어짐)으로 이동한다고 주장 할 수 있습니다. 다른 한편으로, 당신이 이것을하지 않으면, 당김이 빈혈 도메인 모델 쪽으로 향한다는 것은 확실히 맞습니다 .
나는 DDDD에 대한 Greg Young의 (포기한) 논문을 보았을 때까지 오랫동안이 모든 문제를 겪었습니다 . 그는 왜 고정 관념적인 n-tier / n-layer 아키텍처가 항상 CRUDy (따라서 오히려 빈약함 )인지 설명합니다.
도메인 객체를 명사 대신 명령 및 이벤트 로 모델링하는 데 초점을 맞추면 적절한 객체 지향 도메인 모델을 구축 할 수 있습니다.
두 번째 질문은 답하기가 더 쉽습니다. 언제든지 Abstract Factory를 사용하여 런타임에 인스턴스를 만들 수 있습니다 . Castle Windsor를 사용하면 Typed Factory Facility를 사용하여 수동으로 공장을 구현해야하는 부담을 덜어줍니다.
답변
나는 이것이 오래된 게시물이라는 것을 알고 있지만 추가하고 싶었습니다. 도메인 엔터티는 ctor에서 추상화 된 저장소를 전달하더라도 자체적으로 유지되지 않아야합니다. 내가 제안하는 이유는 이것이 단순히 SRP를 위반하는 것이 아니라 DDD의 집계에 위배된다는 것입니다. 설명하겠습니다. DDD는 본질적으로 깊은 그래프가있는 복잡한 앱에 적합하므로 집계 또는 복합 루트를 사용하여 기본 “자식”에 대한 변경 사항을 유지합니다. 따라서 개별 어린이에게 지속성을 주입 할 때 우리는 어린이와 라이프 사이클 또는 집계를 “담당”해야하는 컴포지트 또는 집계 루트. 물론 복합 루트 또는 집계는 자체 그래프를 유지하지 않습니다. 다른 하나는 DDD 개체의 종속성을 주입하는 것입니다. 주입 된 도메인 개체는 상태를 수화하기 위해 다른 이벤트가 발생할 때까지 효과적으로 상태가 없습니다. 코드 소비자는 캡슐화를 위반하는 비즈니스 동작을 호출하기 전에 먼저 도메인 개체를 초기화하거나 설정해야합니다.