나는 데이터베이스에 연결하고 제공된 표준을 기반으로 특정 제품을 선택하고이 제품을 사용하여 처리하는 간단한 콘솔 응용 프로그램을 작성했습니다. 나는이 클래스의 인스턴스에 명령 줄 인수를 저장하고있다 :생성자 삽입 및 주입되는 생성자의 생성
public class Arguments
{
public string ConnectionString { get; set; }
public int ProductId { get; set; }
public string ProductName { get; set; }
}
어떤 시점에서, 나는 데이터베이스에서 제품을 가져해야합니다. 그 내용은 다음 저장소를 사용하고 있습니다 :
다음public interface IProductRepository
{
Product GetById(int productId, string connectionString);
Product GetByName(string productName, string connectionString);
}
, 나는 그것을 사용하는 클래스, 예에 저장소의 구현 주입 :
public class ProductProcessor
{
private readonly IProductRepository productRepository;
public ProductProcessor(IProductRepository productRepository)
{
this.productRepository = productRepository;
}
public void Process(Arguments arguments)
{
Product productToProcess;
if (!string.IsNullOrEmpty(arguments.ProductName))
{
productToProcess = productRepository.GetByName(arguments.ProductName, arguments.ConnectionString);
}
else
{
productToProcess = productRepository.GetById(arguments.ProductId, arguments.ConnectionString);
}
// ....
}
}
이 작동하는지,하지만 난 돈 '무엇을 디자인에 관해서는 IProductRepository
의 모든 메소드가 connectionString
인수를가집니다. 반군 의존성 주입 없었다 경우에, 나는 아마 다음과 같이 그것을 다시 것입니다 : 이것은 간단하고 사용하기 쉬운 인터페이스를 가지고 나를 수
public void Process(Arguments arguments)
{
Product productToProcess;
ProductRepository productRepository = new ProductRepository(arguments.ConnectionString);
if (!string.IsNullOrEmpty(arguments.ProductName))
{
productToProcess = productRepository.GetByName(arguments.ProductName);
}
else
{
productToProcess = productRepository.GetById(arguments.ProductId);
}
// ....
}
. 물론 ProductRepository
에는 매개 변수없는 생성자가 없으므로 DI 컨테이너와 함께 사용하기가 어렵습니다. 이상적으로는 두 세계에서 가장 좋은 점, 즉 ProductRepository
을 생성자의 연결 문자열로 초기화하고 해당 메서드에서 연결 문자열을 제거하고 싶습니다. 이것을 달성하는 가장 좋은 방법은 무엇입니까?
어떤 접근 방식은 내가 이미 고려했습니다
- 는 기본적으로 생성자의 역할을 할 것
IProductRepository
에 방법Initialize(string connectionString)
를 추가합니다. 명백한 단점은GetById
또는GetByName
메서드에서 아무 것도 수행하기 전에Initialize
이 호출되었는지 여부를 확인해야한다는 것입니다. ProductRepository
을 인스턴스화하는 대신 생성자 삽입을 사용하고 Service Locator 패턴을 사용하지 마십시오. 나는 Service Locator를 많이 좋아하지 않지만 이것은 아마도 유일한 해결책 일 것입니다.
더 좋은 대안이 있습니까?
편집 : 나는 좀 더 문맥을 게시 한 것을보고 답변에서. DI 컨테이너로 Ninject를 사용하고 있습니다. 내 Program.cs에서 Main
방법에서, 나는 컨테이너에 모든 종속성을 등록하고 응용 프로그램에 대한 진입 점 역할을하는 클래스의 인스턴스 :
public class MainClass
{
private readonly IArgumentsParser argumentsParser;
private readonly IProductProcessor productProcessor;
public MainClass(IArgumentsParser parser, IProductProcessor processor)
{
argumentsParser = parser;
productProcessor = processor;
}
public void Start(string[] args)
{
Arguments parsedArguments = argumentsParser.Parse(args);
productProcessor.Process(parsedArguments);
}
}
:
public static void Main(string[] args)
{
StandardKernel kernel = new StandardKernel();
kernel.Bind<IArgumentsParser>().To<IArgumentsParser>();
kernel.Bind<IProductProcessor>().To<ProductProcessor>();
kernel.Bind<IProductRepository>().To<ProductRepository>();
MainClass mainClass = kernel.Get<MainClass>();
mainClass.Start(args);
}
MainClass
은 다음과 같습니다를
이렇게하면 Ninject에 의존하고 전체 그래프를 한 곳에서만 만들 수 있습니다 (Main
메서드). 나머지 응용 프로그램에서는 DI 및 컨테이너에 대해 아무것도 모릅니다.
가능하면이 방법을 사용하고 싶습니다.
연결 문자열 누출 추상화도 아닌가요? 너는 너의 책에서 이것을 진술했다. 아마도 이런 경우 (사용자 입력으로 연결 문자열)의 경우 명확하지 않습니다. – mnn
예, 당신은 그것을 주장 할 수 있습니다. 그러나 방금 모든 것을 다 망치지 않기 위해 그 부분에 OP의 객체 모델을 사용했습니다. :) –