2009-04-27 9 views
2

종속성 주입에 관한 질문이 있습니다. 확인공장 패턴 및 종속성 주입에 대한 Demeter의 법

private HttpService httpService; 
... 
List<WebGetTask> list = new ArrayList<WebGetTask>(); 
for(...) 
{ 
    list.add(new WebGetTask(httpService)); 
} 
... 

:

는 WebGetTask

WebGetTask이 HttpService를

나쁜 코드 1 코드에 대한 의존성을 필요, 내가 가 호출 클래스를 생성하고 싶은 말은.

private WebGetTaskFactory webGetTaskFactory; 
... 
List<WebGetTask> list = new ArrayList<WebGetTask>(); 
for(...) 
{ 
    list.add(webGetTaskFactory.newTask()); 
} 
... 

내가이 더 나은 생각 때문에 : 나는 새로운 WebGetTask의 생성을 제외하고, HTTPService를 주입되어 있지만 사용하지 않기 때문에이

확인 나쁜 코드 2 코드, 나쁜 알고 우리는 하지만 ... 하지만 ..

내가 서있어 곳에서

, 내가 WebGetTaskFactory 우리는 여전히 HttpService를하고 일을하지 아무것도 주입하는 것을 볼 수 있습니다 공장을 사용 새로운 WebGetTask 그래서

창조의 목적을 제외하고 그것을 내 문제는 내가 팩토리 클래스 (WebGetTaskFactory)를 설계 어떻게 입니다 을 요약하자면, 작성한 새로운 객체 (WebGetTask) 새로운 객체 종속성을 필요로 할 때 (HttpService) 단순히 그들의 의존성 (HttpService) 주입 및 전달없이 그들의 생성자에? 또는 오히려, 이것을하는 방법입니까? 그렇다면 모두 좋고, 그렇지 않다면 DI와 공장 패턴을 올바르게 사용하는 방법을 알려주십시오. 덕분에 .

답변

8

표시 한 코드는 DownloadManager 클래스의 일부이며 생성자를 통해 종속성을 주입한다고 가정합니다.

IHttpService httpService = new HttpService(); 
IWebGetTaskFactory webGetTaskFactory = new WebGetTaskFactory(httpService); 
IDownloadManager downloadManager = new DownloadManager(webGetTaskFactory); 

DownloadManager 클래스 만 IWebGetTaskFactory 인터페이스에 대해 알고 :이 경우, 나는이처럼 보이는 모든 것을 함께 접착제 시동 코드를 기대. IHttpService에 대해 알지 못하므로 Demeter의 법칙을 만족시킵니다.

편집 : 질문을 다시 읽은 후에는 새로운 WebGetTask에 전달하는 것을 제외하고는 공장에서 HttpService를 "사용하고 있지 않다"고 우려하는 것 같습니다. 괜찮습니다. WebGetTaskFactory 및 WebGetTask는 모두 자신의 작업을 수행하기 위해 HttpService 인스턴스가 필요합니다. 이것은 데메테르의 법을 위반하는 것이 아닙니다.

+0

. webGetTaskFactory 내에서 httpService를 사용하지 않는 것에 대해 걱정했습니다. 그래서 "webGetTaskFactory"에 "httpService"객체를 삽입하고, "webGetTaskFactory"는 새로운 "webGetTask"를 생성 할 때만 "httpService"를 사용합니다. 그리고 이것은 괜찮습니다. 시원한. 이것을하기위한 "텍스트 북"예제가 더 있습니까? 또는 생성자에 대한 특정 종속성이 필요한 객체를 만드는 가장 일반적인 방법입니까? –

+0

생각해 보면 공장에서는 "런타임 종속성 주입"을 수행합니다. 디자인 타임이 아닌 런타임에 동적으로 생성 된 개체에 대한 종속성 주입 패턴을 따르려면 자연스러운 방법입니다. –

3

좋아, LoD에서 구현 객체, 즉 생성자에 "플러그인"을 전달하는 것에 대해 특별히 잘못된 것은 없습니다. 중요한 것은 클래스의 인터페이스가 구현에 대해 많이 알려주지 않는다는 것입니다.

WebGetTask에 대한 인터페이스가 HttpService의 정확한 구현에 의존하는 경우 은 Demeter의 법칙을 위반합니다.

여기 트릭은 WebGetTask의 인터페이스 서명에 대해 생각하는 것입니다. 이름 자체는 (1) 웹에 고유 한 것으로 정의 된 클래스를 정의하고 (2) 대신 동사 인 데 메타의 법칙 또는 최소한의 지식의 원칙을 따르지 않는다고 제안합니다. 명사의.

이제는 그 중 어느 것도 틀린 것은 아니지만 둘 다 "OO 냄새"라고 생각하면 충분히 생각할 수없는 징후가됩니다.

그럼 디자인을 "리팩터링"해보 죠. 우선, 관련된 "웹"이없는 GetTask에 대해 생각해보십시오. 그런 다음 생성시 또는 나중에 서비스 객체를 작성하여 전달할 수 있습니다. HttpService의 경우에는 문제가 없지만 클래스 사용자는 커버 아래에있는 내용에 대한 정보가 필요하지 않습니다.

두 번째 것은 명사로합시다. TaskFactory라고 부르세요. 당신의 직관은 바로 거기에서 당신을 이끌고있었습니다. IOService를 사용하는 ctor로, 저는 HttpService에 의해 구현 된 추상 인터페이스로 발명했습니다.,

class Task { ... } 
class TaskFactory { 
    public TaskFactory(IOServer svc){...} 
    public Task get(){...} 
} 

을하고 지금

TaskFactory fac = new TaskFactory(new HttpService()); 
Task tsk = fac.get(); 

를 작성하여 사용 :

지금, 당신은 (이것은 자바/C++ 의사 코드의 종류는, 구문의 세부 사항에 대해 흥분하지 않는 것입니다)이 우리는 TaskFactory의 내장, IO 서비스 및 태스크에 대해 최소한의 지식을 제공합니다.

1

DI의 두 가지 방법이 있습니다. 첫 번째 것은 하나 또는 두 개의 객체가 주입 될 때 유용하며 생성자가 하나 인 경우입니다 (실제로 필요한만큼의 세터).

원칙적으로 DI에 대한 팩토리 방법을 사용하려는 경우 생성자 기반의 방법과 동일합니다.

list.add(new WebGetTask(httpService)) ; 

예 2, 세터의 DI에 대한 : 만들 때 몇 가지 큰 논리를 사용해야하는 경우에

WebGetTask webGetTask = new WebGetTask(); 
webGetTask.setHttpService(httpService); 
// set other dependencies 
list.add(webGetTask); 

공장 방법에 가장 생성자 DI에 대한

예 1, 다르게 행동 할 수도 있지만 동일한 인터페이스를 갖는 객체이므로 LoD. 팩토리 매개 변수를 기반으로 동적으로 구현 된 DownloadManager 인터페이스가 있다고 가정합니다.

실시 예 3에서, 생성 로직은 공장 메소드에 캡슐화 :

public static DownloadManager createDownloadManager(HttpService httpService){ 

    if(null!=httpService){ 
     WebGetTask webGetTask = new WebGetTask(); 
     webGetTask.setHttpService(httpService); 
     // set other dependencies 
     return new DownloadManagerImpl1(webGetTask); 
    } else { 
     return new DownloadManagerImpl2(); 
    } // if-else 
} 
예를
관련 문제