0

나는 RequestHandler 클래스와 RequestListener 클래스를 가지고있다. RequestHandler는 RequestListener를 생성하고 RequestListener를 자신에 대한 참조로 전달합니다. RequestListener는 RequestHandler의 메소드를 호출하여 처리 될 때 여러 유형의 요청 (예 : handleTypeARequest(), handleTypeBRequest() 등)을 처리합니다. 이 둘 사이에 단단한 결합을 의미하며, 일반적으로 코드 냄새로 간주이 순환 양방향 종속성을 어떻게 해결할 수 있습니까?

class RequestHandler { 
    RequestListener requestListener; 
    ... 
} 

class RequestListener { 
    RequestHandler requestHandler; 
    ... 
} 

: 불행히도, RequestHandler를도 그래서 순환 종속성이 (예 processNextRequest())에 RequestListener 메소드를 호출한다.

한 가지 해결책은 다른 방법 대신 각 요청을 캡슐화하기 위해 서로 다른 개체를 사용하는 것입니다. RequestListener는 메시지가 표시되면 요청을 처리하고 요청 객체의 일부 유형을 반환 할 수 있습니다. 불행히도, 나는이 접근법을 정말 좋아하지 않습니다. 부분적으로는 더 많은 객체와 클래스의 복잡성이 추가되고 부분적으로는 성능 문제 (여기서는 중요 함) 때문입니다. RequestHandler에서 handleXXXRequest() 메소드를 직접 호출하는 것은 많은 수의 객체를 생성하는 것보다 훨씬 빠르며 필요할 때까지 버퍼를 유지하는 스택을 유지하는 것보다 훨씬 빠릅니다.

이 문제에 대한 다른 해결책이 있습니까? 또한 은 정말로에 문제가 있습니까?

+0

요청 청취자가 요청 처리를 담당해야합니까? 청취자는 청취에만 책임이 있습니다. "요청 처리자"는 청취자의 말을 처리하거나 "처리"해야합니다. –

답변

3

그래, 이것이 정말로 문제가됩니까?

당신이 말한 것처럼, 모두 < -> 자식 참조에 문제가 있으며, 둘 다 서로를 참조합니다. 나는 정말로 여기에 문제가 있다고 생각하지 않는다.

1

프로그래밍 언어를 사용하면 클래스 선언을 전달할 수 있으므로 구문 오류 부분을 지나칠 수 있습니다. 이 C++라면

, 나는 같은 것을 할 것입니다 :

class RequestListener; 

class RequestHandler { 
    RequestListener *requestListener; 
    /* ... */ 
} 

class RequestListener { 
    RequestHandler *requestHandler; 
    /* ... */ 
} 

을하지만, 당신이 무한히 큰 구조를 얻을 것이기 때문에 당신이 (재귀 적으로 객체를 둥지에 자신을 시도하는 경우가 문제가 될 것이라는 점에 유의) :

class RequestListener; 

class RequestHandler { 
    RequestListener requestListener; 
     // the compiler will complain about an incomplete type here 
    /* ... */ 
} 

class RequestListener { 
    RequestHandler requestHandler; 
    /* ... */ 
} 

개체가 서로 포함되지 않고 서로 참조하기를 원하기 때문에 괜찮을 것입니다.

+0

죄송합니다. 명확하지 않았습니다. 문제는 단단히 결합하고 문법 오류가 아닌 최소화하는 방법입니다. 그것은 현재 (그리고 작동) 벌금을 컴파일합니다. – james

+0

명확한 질문을 편집했습니다. – james

0

이벤트를 사용하면 명시 적으로 클래스를 참조하지 않고도 특정 상태 변경 사항에 대해 다른 개체에 알릴 수 있습니다.

class RequestListener 
{ 
    public event EventHandler<RequestReceivedEventArgs> RequestReceived; 

    public void ProcessNextRequest(object sender, RequestHandledEventArgs e) 
    { 
     // Process next request. 
    } 
} 

class RequestDispatcher 
{ 
    public event EventHandler<RequestHandledEventArgs> RequestHandled; 

    public void DispatchRequest(object sender, RequestReceivedEventArgs e) 
    { 
     // Invoke correct RequestHandler class/method. 

     // Raise RequestHandled event when request handler has finished. 
    } 
} 

var listener = new RequestListener(); 
var dispatcher = new RequestDispatcher(); 

// Subscribe to each other's events. 
listener.RequestReceived += dispatcher.DispatchRequest; 
dispatcher.RequestHandled += listener.ProcessNextRequest; 

상기 C# 예제는 다음 .NET Framework Guidelines 따라서 아주 장황 있지만 클래스 간 디커플링을 도시한다. 또한 청취자가 처리하도록 대신 올바른 처리기를 호출하는 클래스 인 RequestDispatcher을 도입했습니다.

추가 클래스를 만들지 않으려면이 모델을 실제로 필요한 것만 스트립 할 수 있습니다. 예를 들어 TypeARequestReceivedTypeBRequestReceived 이벤트를 수신기에 노출 할 수 있습니다. 그런 다음 요청 핸들러 메소드는 이러한 이벤트에 직접 등록 할 수 있습니다.

+0

'디스패처'와 OP의 '처리기'가 같은 목적을 가지고 있는지 잘 모르겠습니다. – izb

+0

아니요, 그렇지 않습니다. OP의 예에서 청취자는 올바른 핸들러를 호출 할 책임이 있습니다. 디스패처로이 논리를 추출했습니다. 운영자는 OP의 핸들러 중 하나에게 요청을 위임 할 책임이 있습니다. 디스패처에서'RequestHandled' 이벤트가 어쩌면 어수선하지만 가능한 한 짧은 예제를 유지하려고했습니다. –

관련 문제