팩토리 패턴과 함께 Dependency Injection을 사용하는 방법


10

주어진 유형의 파일을 구문 분석하는 모듈을 고려하십시오. 이미 이상 설명대로 나는이 문제를 해결하기 위해 전략 패턴을 사용하여 생각하고 여기에 . 이 질문을 진행하기 전에 링크 된 게시물을 참조하십시오.

product.xml 파일의 내용이 필요한 클래스 B를 고려하십시오. 이 클래스는 XML 파일을 구문 분석하기 위해 구문 분석기 인터페이스의 적절한 구체적 구현자를 인스턴스화해야합니다. 클래스 B가 "has-a"팩토리가되도록 적절한 구현 도구의 인스턴스화를 팩토리에 위임 할 수 있습니다. 그러나 클래스 B는 구체적인 구현자를 인스턴스화하기 위해 팩토리에 "의존"합니다. 이것은 클래스 B의 생성자 또는 setter 메소드가 팩토리로 전달되어야 함을 의미합니다.

따라서 파일을 구문 분석해야하는 팩토리와 클래스 B는 서로 밀접하게 연결됩니다. 지금까지 설명한 내용에 대해 완전히 틀릴 수 있음을 이해합니다. 주입 될 종속성이 팩토리 인 시나리오에서 종속성 주입을 사용할 수 있는지 여부와 이것을 구현하는 올바른 방법이 무엇인지 알고 싶습니다. 그래서 단위 테스트에서 팩토리 조롱과 같은 영역을 활용할 수 있습니다.

답변:


8

이를 수행하는 올바른 방법은 인터페이스에 의존 한 다음 해당 인터페이스의 구현을 클래스 B에 삽입하는 것입니다.

인터페이스는 당신이 의존 할 수있는 가장 얇은 것입니다. 나는 연기를 없애려고 노력하는 것과 같습니다. 코드는 무언가에 연결해야합니다. 그렇지 않으면 아무것도하지 않습니다. 그러나 인터페이스에 연결하는 것은 가능한 한 분리되어 있지만 인터페이스는 원하는 모든 기능을 제공 할 수 있습니다.

따라서 클래스 B의 생성자가 필요한 클래스에 대한 인터페이스를 가져 오도록하고 팩토리가 해당 클래스를 인터페이스의 구현 자로 생성하도록하십시오. 팩토리에 의존하지 말고, 인터페이스에 의존하고, 팩토리가 해당 팩토리의 구현을 제공하게하십시오.

예, 의존성 주입을 사용하지만 아무 문제가 없습니다. 의존성 주입 (특히 간단한 생성자 주입)은 "정상적인"작업 방식이어야합니다. 앱에서 최신 정보를 가능한 한 멀리 되돌리고 (첫 번째 줄에 가까움) 간단히 물건 main을 만들기 위해 설계된 클래스에서 새 전화를 숨기십시오.

결론 : 의존성을 주입하는 것을 망설이지 마십시오. 그것은 정상적인 일을하는 방식이어야합니다.


생성자 주입은 가능한 한 오랫동안 새로운 것을 시작합니까?
JeffO

잘못 입력했습니다. "가급적 앱에서 최대한 멀리"라고 말하도록 수정했습니다.
Nick Hodges

예. 팩토리 대신 파서 인터페이스에 의존하려고 생각했습니다. 이제 다른 클래스가 클래스 B를 사용하는 경우 클래스 B가 의존하는 인터페이스에 의존해야합니다. 이것은 최상위 수준까지 계속 이어질 것입니다. 이 최상위 클래스는 마지막으로 팩토리를 사용하여 적절한 구문 분석기 인스턴스를 인스턴스화해야합니다. 최상위 클래스가 팩토리에 의존해야합니까, 아니면 메소드 내부에서 팩토리를 직접 사용해야합니까?
CKing 2019

1
잘 말했다 : 의존성 주입을 주저하지 말고
Signcodeindie

9

나는 당신의 전제가 여기에서 약간 혼란스러워한다고 생각합니다. 공장을 주입하는 것에 대해 이야기하지만, 공장 패턴은 DI 프레임 워크가 널리 퍼지지 않았을 때 의존성 주입 프레임 워크가 수행하는 것의 하위 세트를 수행하는 것이 목적인 창조 패턴입니다. 그런 이유로 유용합니다. 그러나 DI 프레임 워크가있는 경우 DI 프레임 워크가 공장이 달성 한 목적을 달성 할 수 있으므로 더 이상 팩토리가 필요하지 않습니다.

즉, 의존성 주입과 일반적으로 사용하는 방법에 대해 조금 설명하겠습니다.

의존성 주입을 수행하는 방법에는 여러 가지가 있지만 가장 일반적인 방법은 생성자 주입, 속성 주입 및 직접 DIContainer입니다. 속성 주입은 대부분 잘못된 접근 방식이므로 (제대로 올바른 접근 방식) 생성자 주입에 대해 이야기하겠습니다. DIContainer 액세스는 다른 접근 방식 중 하나를 절대 수행 할 수없는 경우를 제외하고는 바람직하지 않습니다.

생성자 주입은 의존성에 대한 인터페이스와 해당 의존성에 대한 구체적인 구현을 알고있는 DIContainer (또는 팩토리)가있는 곳이며, 구성 시간에 구현시 공장에서 구현할 때 해당 인터페이스에 의존하는 객체가 필요한 경우 그것.

IDbConnectionProvider connProvider = DIContainer.Get<IDbConnectionProvider>();
IUserRepository userRepo = new UserRepository(connProvider);
User currentUser = userRepo.GetCurrentUser();

많은 DI 프레임 워크는 DIContainer가 UserRepository의 생성자를 검사하여 구체적인 구현을 알고있는 인터페이스를 검사하고 자동으로 사용자에게 전달하는 위치로이를 단순화 할 수 있습니다. DI와 IoC는 둘 다 많이 교환되고 모호한 차이가있는 용어이지만이 기술을 제어의 반전이라고합니다.

이제 가장 중요한 코드가 DIContainer에 액세스하는 방법이 궁금하다면,이를 액세스하기위한 정적 클래스를 가질 수도 있고, 더 적절한 것은 대부분의 DI 프레임 워크에서 DIContainer를 새로 만들 수 있다는 것입니다. 주어진 인터페이스에 대해 구체적으로 알고있는 유형의 내부 싱글 톤 사전에 대한 랩퍼.

즉, 코드에서 원하는 곳 어디에서나 DIContainer를 새로 만들 수 있고 인터페이스와 콘크리트 관계를 알기 위해 이미 구성한 것과 동일한 DIContainer를 효과적으로 얻을 수 있습니다. DIContainer를 코드와 직접 상호 작용해서는 안되는 부분에서 숨기는 일반적인 방법은 필요한 프로젝트 만 DI 프레임 워크에 대한 참조를 갖도록하는 것입니다.


나는 첫 번째 단락에 전적으로 동의하지 않습니다. DI 컨테이너에 의해 주입되는 팩토리 (인터페이스 구현)에 의존하는 시나리오가 여전히 있습니다.
Piotr Perak

OP가 DI 프레임 워크 또는 DI 컨테이너에 대해 언급하지 않았기 때문에 요점을 놓친 것 같습니다.
Doc Brown

@Jimmy Hoffa 매우 흥미로운 점을 지적했지만 Spring과 같은 IoC 컨테이너와 Dependency Injection의 개념을 알고 있습니다. 내 관심사는 IoC 프레임 워크를 사용하지 않는 시나리오에 관한 것이 었습니다.이 경우 종속성을 인스턴스화 할 클래스를 작성해야합니다. 클래스 A가 인터페이스 B에 의존하고 클래스 C가 클래스 A를 사용하는 경우 클래스 C는 인터페이스 B에 의존합니다. 누군가 클래스 C에 클래스 B를 부여해야합니다. 클래스 C는
cla

클래스 A가 인터페이스 B에 의존하고 클래스 C가 클래스 A를 사용하는 경우 클래스 C는 인터페이스 B에 의존합니다. 누군가 클래스 C에 인터페이스 B를 제공해야합니다. 클래스 C에 인터페이스 B에 의존해야하는지 또는 인스턴스화 한 클래스에 의존해야합니까? 의존성 즉 공장. 귀하의 답변에이 질문에 대한 답변이 있지만 정보 과부하가 발생했습니다 :)
CKing

나는 같은 @bot, 그것은 독 브라운이 언급 한 모든 상황에서 사실이 아니다, 그러나보기 내 코드 샘플에서와 대체 당신이 DI 컨테이너의 기능의 일부로서 공장을 치료할 수 많은 부분에서, 서문에서 말했다 DIContainerDbConnectionFactory및 개념 여전히 DI / Factory / etc에서 구체적인 구현을 검색하여 시공 시점에 해당 유형의 소비자에게 전달할 것입니다.
Jimmy Hoffa

5

다른 것을 전달하는 것처럼 의존성 주입을 통해 팩토리를 전달할 수 있습니다. 상황의 재귀가 혼동되지 않도록하십시오. 구현에 대해 다른 말을해야합니다. 종속 주입을 수행하는 방법을 이미 알고 있습니다.

나는 DI를 사용하여 공장을 꽤 규칙적으로 주입합니다.


1
클래스가 팩토리에 의존하는 경우 해당 클래스를 단위 테스트 할 때 팩토리를 조롱해야합니다. 어떻게 그렇게합니까? 클래스가 팩토리 인터페이스에 의존하게 하시겠습니까?
CKing 2019

4

공장을 주입하는 데 아무런 문제가 없습니다. '부모'객체를 빌드하는 동안 어떤 종류의 종속성이 필요한지 결정할 수없는 경우 표준 방법입니다. 나는 모범이 그것을 가장 잘 설명 할 것이라고 생각한다. Java를 모르기 때문에 C #을 사용합니다.


class Parent
{
    private IParserFactory parserFactory;
    public Parent(IParserFactory factory)
    {
        parserFactory = factory
    }

    public ParsedObject ParseFrom(string filename, FileType fileType)
    {
        var parser = parserFactory.CreateFor(fileType);
        return parser.Parse(filename);
    }
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.