如何解决这种循环的双向依赖?

时间:2010-07-28 20:03:57

标签: language-agnostic circular-dependency circular-reference

我有一个RequestHandler类和一个RequestListener类。 RequestHandler创建一个RequestListener并将其引用传递给它自己。 RequestListener依次调用RequestHandler上的方法来处理处理它们时不同类型的请求(例如handleTypeARequest(),handleTypeBRequest()等)。不幸的是,RequestHandler还调用RequestListener上的方法(例如processNextRequest()),所以我有一个循环依赖:

class RequestHandler {
   RequestListener requestListener;
   ...
}

class RequestListener {
   RequestHandler requestHandler;
   ...
}

这意味着两者之间的联系更紧密,通常被认为是代码气味。

一种解决方案是使用不同的对象来封装每个请求而不是不同的方法。当提示时,RequestListener可以处理请求并为其返回某种类型的Request对象。不幸的是,我并不喜欢这种方法,部分原因是因为更多的对象和类的复杂性,部分是因为性能问题(这里很重要);直接在RequestHandler上调用handleXXXRequest()方法比创建一堆对象要快得多,并且可能还需要维护一个堆栈来缓冲它们直到需要它们。

这个问题是否有其他解决方案,而且真的是一个问题吗?

3 个答案:

答案 0 :(得分:3)

是的,这真的是个问题吗?

就像你说的那样,父母< - >存在问题。儿童参考,两者都互相参照。我不相信这里真的有问题。

答案 1 :(得分: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;
    /* ... */
}

由于你只是希望对象互相引用而不是相互包含,所以你应该没问题。

答案 2 :(得分: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个事件。然后您的请求处理程序方法可以直接订阅这些事件。