При создании архитектуры типа «Регистрация обработчиков», как я должен передавать обработчики? - PullRequest
1 голос
/ 01 февраля 2011

Я в целях обучения пишу протокол клиент-сервер UDP на c ++, где связь между серверным компонентом моего приложения и остальной частью приложения осуществляется с помощью обработчиков.

Например, я мог бы зарегистрировать компонент Authorization для значения 1, а компонент TextMessage для значения 2. Затем клиент сначала отправляет одно или два сообщения в компонент Authorization для входа в систему, а затем начинает отправку текстовых сообщений в обработчик TextMessage. .

Вот что у меня сейчас:

class NetworkHandler {
    virtual void handleMessage(const endpoint & endpoint, const buffer & message) = 0;
};

Любой класс, который хочет зарегистрироваться в качестве компонента, просто создает подкласс NetworkHandler и вызывает

udpServer.addHandler(handler);

Тем не менее, у меня есть несколько проблем с решением, как я должен передать обработчики, будучи новичком и все.

Должен ли я передать обработчик по ссылке? Это легко и удобно, но в игру вступает вопрос о праве собственности - вызывающей функции, вероятно, не нужно беспокоиться о том, чтобы хранить ссылки без причины.

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

Что меня интересует, так это то, что является наилучшей практикой для такого рода ситуаций? Извините за стену текста.

Ответы [ 3 ]

0 голосов
/ 01 февраля 2011

У вас есть несколько вариантов.

  • Кто бы ни выделял, удаляет.Передайте указатель / ссылку, верните указатель / ссылку, когда отсоединены.
  • Владение сервером.Передав указатель на выделенный экземпляр, сервер отвечает за удаление при отсоединении.
  • Smart Pointer (например, повышение shared_ptr или другое).Пока у кого-то есть ссылка, вам не нужно беспокоиться об управлении памятью (по большей части).

Я недавно завершил такую ​​систему и использовал для нее умный указатель, который оказалсябыть самым простым и не требующим дополнительной документации.

0 голосов
/ 01 февраля 2011

Другими словами, вопрос в том, является ли компонент сервера владельцем компонента приложения или наоборот, верно?

На мой взгляд, это как стек, с уровнем прикладной логики, находящимся на вершине сетевого транспортного уровня. Сетевой уровень - это механизм более низкого уровня, который не знает логику приложения и может использоваться для создания нескольких приложений с различной логикой приложения поверх него, поэтому для него было бы неудобно создавать и владеть уровнем приложения. Прикладной уровень, с другой стороны, знает, какие компоненты ему необходимы для реализации необходимой логики. Таким образом, он может создавать и владеть сетевым уровнем.

Если вы хотите четко разделить слои или если существует несоответствие времени жизни прикладного уровня и сетевого уровня, имеет смысл иметь фрагмент кода, который создает оба компонента (объекта) и связывает их вместе через интерфейсы, и этот кусок кода может владеть обоими. Обычно этот фрагмент кода является функцией main (), которая читает командную строку / файл конфигурации, создает и настраивает необходимые объекты, связывает их вместе и запускает цикл обработки событий (select / epoll /...).

В таком случае вам не нужно связывать интерфейсы обратного вызова с проблемами владения и загромождать их интеллектуальными указателями, просто передавайте указатель или ссылку на интерфейсы через обратные вызовы. Просто убедитесь, что вы не вызываете обратные вызовы в конструкторах или деструкторах долгоживущих объектов, чтобы вы могли строить и разрушать граф вызовов в наиболее удобном порядке.

0 голосов
/ 01 февраля 2011

Если сомневаетесь, поделитесь с shared_ptr. Это самодокументируется и почти всегда работает за счет некоторой косвенности указателя и одного / двух выделений памяти.

...