DI가 기술이 아닌 패턴과 원리 에 관한 것임을 이해하면 실제로는 간단합니다 .
DI 컨테이너와 무관하게 API를 디자인하려면 다음 일반 원칙을 따르십시오.
구현이 아닌 인터페이스로 프로그램
이 원칙은 실제로 Design Patterns 의 인용 (메모리에서 인용) 이지만 항상 실제 목표가 되어야합니다 . DI는 그 목적을 달성하기위한 수단 일뿐 입니다.
할리우드 원리 적용
DI 용어의 할리우드 원칙은 다음과 같이 말합니다. DI 컨테이너를 호출하지 마십시오 .
코드 내에서 컨테이너를 호출하여 종속성을 직접 요청하지 마십시오. Constructor Injection 을 사용하여 암시 적으로 요청하십시오 .
생성자 주입 사용
의존성이 필요한 경우 생성자를 통해 정적으로 요청 하십시오.
public class Service : IService
{
private readonly ISomeDependency dep;
public Service(ISomeDependency dep)
{
if (dep == null)
{
throw new ArgumentNullException("dep");
}
this.dep = dep;
}
public ISomeDependency Dependency
{
get { return this.dep; }
}
}
서비스 클래스가 불변을 어떻게 보장하는지 주목하십시오. 인스턴스가 생성되면 Guard Clause와 readonly
키워드 의 조합으로 인해 종속성을 사용할 수 있습니다 .
수명이 짧은 객체가 필요한 경우 Abstract Factory를 사용하십시오.
Constructor Injection으로 주입 된 종속성은 오래 지속되는 경향이 있지만 때로는 수명이 짧은 객체가 필요하거나 런타임에만 알려진 값을 기반으로 종속성을 구성해야합니다.
자세한 내용은 이것을 참조하십시오.
마지막 책임있는 순간에만 작성
끝까지 개체를 분리하십시오. 일반적으로 응용 프로그램의 진입 점에서 모든 것을 기다렸다가 연결할 수 있습니다. 이것을 컴포지션 루트 라고합니다 .
자세한 내용은 여기 :
외관을 사용하여 단순화
결과 API가 초보자 사용자에게 너무 복잡해 졌다고 생각되면 공통 종속성 조합을 캡슐화하는 Facade 클래스를 항상 제공 할 수 있습니다 .
높은 수준의 검색 가능성을 가진 유연한 Facade를 제공하기 위해 Fluent Builders 제공을 고려할 수 있습니다. 이 같은:
public class MyFacade
{
private IMyDependency dep;
public MyFacade()
{
this.dep = new DefaultDependency();
}
public MyFacade WithDependency(IMyDependency dependency)
{
this.dep = dependency;
return this;
}
public Foo CreateFoo()
{
return new Foo(this.dep);
}
}
이를 통해 사용자는 다음과 같이 작성하여 기본 Foo를 만들 수 있습니다
var foo = new MyFacade().CreateFoo();
그러나 커스텀 의존성을 제공 할 수 있다는 것을 발견 할 수있을 것입니다.
var foo = new MyFacade().WithDependency(new CustomDependency()).CreateFoo();
MyFacade 클래스가 다양한 종속성을 캡슐화한다고 생각한다면 확장 성을 검색하면서도 적절한 기본값을 제공하는 방법이 명확하기를 바랍니다.
FWIW는이 답변을 작성한 후 여기에있는 개념을 확장하여 DI-Friendly Libraries 에 대한 더 긴 블로그 게시물 과 DI-Friendly Frameworks에 대한 관련 게시물을 작성했습니다 .