0

У меня есть класс RequestHandler и класс RequestListener. RequestHandler создает RequestListener и передает ему ссылку на себя. RequestListener, в свою очередь, вызывает методы на RequestHandler для обработки запросов разных типов при их обработке (например, handleTypeARequest(), handleTypeBRequest() и т. Д.). К сожалению, RequestHandler также вызывает методы RequestListener (например processNextRequest()), так что у меня есть циклическая зависимость:Как можно решить эту круговую двунаправленную зависимость?

class RequestHandler { 
    RequestListener requestListener; 
    ... 
} 

class RequestListener { 
    RequestHandler requestHandler; 
    ... 
} 

Это означает более тесную связь между ними и, как правило, считается кодом запахом.

Одним из решений было бы использование разных объектов для инкапсуляции каждого запроса вместо разных методов. При запросе RequestListener мог обработать запрос и вернуть для него некоторый тип объекта Request. К сожалению, мне не очень нравится этот подход, отчасти из-за дополнительной сложности большего количества объектов и классов и отчасти из-за проблем с производительностью (что важно здесь); вызывающие методы handleXXXRequest() на RequestHandler напрямую намного быстрее, чем создание кучи объектов и, вероятно, также поддерживают стек для их буферизации до тех пор, пока это не понадобится.

Есть ли другие решения этой проблемы, а также, это действительно проблема?

+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, который отвечает за вызов правильного обработчика, вместо того, чтобы позволить слушателю позаботиться об этом.

Вы можете снять эту модель только на то, что вам действительно нужно, если вы не хотите создавать дополнительные классы. Например, вы можете выявить TypeARequestReceived и TypeBRequestReceived событий в вашем слушателе. Затем ваши методы обработчика запросов могут подписаться непосредственно на эти события.

+0

Я не уверен, что ваш «диспетчер» и «обработчик» OP имеют ту же цель. – izb

+0

Нет, они этого не делают. В примере OP слушатель отвечал за вызов правильного обработчика. Я извлек эту логику в диспетчер. Диспетчер отвечает за делегирование запроса одному из обработчиков OP. Событие 'RequestHandled' на диспетчере, вероятно, неуместно, но я хотел, чтобы этот пример был как можно короче. –

 Смежные вопросы

  • Нет связанных вопросов^_^