@xverizex

Как правильней сделать это на си?

Имеется реализация на си для встраивания в проект. Не подходит как библиотека. Надо именно добавлять эти файлы в проект. Я читал книгу по java по паттернам и мне понравился паттерн наблюдатель. Я захотел создать нечто подобное на си. Ну как нечто подобное, чтобы можно было подписаться и получать события. Сама структура создается только в этой реализации, она общая для всей программы. То есть можно из любой точки программы подписаться на издателя. И в любой точке программы можно отправить событие от издателя. Мне пишут что мол можно ошибиться, в указании типа ( type ). Я говорю что можно завести отдельный хедер файл и указать в enum названия издателей. Но мне пишут что это плохо, что программисты будут ошибаться всё равно. Но как только я предлагаю написать нечто подобное на си, то сразу никто не может. Язык плохо знают. Сами пишут на другом языке и показывают как это должно работать. Но я хотел создать универсальные функции, чтобы один раз написал и много раз использовать без переделки кода. Вот раз никто не может показать как правильно сделать на си, то решил задать вопрос здесь. Мне нужно только увидеть объявления функций, без их реализации. Я хочу посмотреть, можно ли сделать лучше, чем есть у меня. Вот проект на github

Вот какие есть функции в заголовке.
/*
 * init_publisher - инициализировать издателя. 
 * @type = это тип издателя. Например в enum указывает enum { TRADE, NEWS }, к каждому издателю можно подписаться нескольким функциям.
 * @subscribe = это функция указатель. в эту фукнцию издатель будет отправлять события и данные.
 */
void init_publisher ( int type, void (*subscribe) (void *event, void *data), void *data );
/*
 * отправить событие.
 * @type = если например в init_publisher вы задали TRADE, то в send_event в TRADE отправяться событие, которое вы укажите.
 * @event = событие. можно передать любые данные.
 */
void send_event ( int type, void *event );
/*
 * отписаться от издателя.
 * @type = тип издателя.
 * @subscribe = функция указатель. её надо указать, чтобы в этом типе удалить эту функцию от подписки.
 * @data = указатель на данные. удалиться подписчик именно с этими данными.
 */
void delete_publisher ( int type, void (*subscribe) ( void *event, void *data ), void *data );
/*
 * удалить всех подписчиков связанных с данной функцией. */
void delete_all_subscribe ( int type, void (*subscribe) ( void *event, void *data ) );
/* удалить абсолютно всех подписчиков привязанных к определенному издателю. */
void delete_all_publisher ( int type );
  • Вопрос задан
  • 94 просмотра
Пригласить эксперта
Ответы на вопрос 1
@res2001
Developer, ex-admin
Правильно пишут. Вас не смущает два void* в callback?
У вас функция принимает 2 параметра на что угодно, хреновая идея. Тут и будут ошибаться.
На сколько я могу судить data - это пользовательские данные, тут void* без вариантов, но можно обозвать например userdata и описать, что userdata в калбэке и в init - это одно и то же и библиотека больше никак не использует этот указатель.
На мой взгляд event вполне можно описать какой-то заранее определенной структурой. Или хотя бы у этой структуры должен быть единый заголовок (включающий тип события и возможно что-то еще общее для всех событий). Посмотрите, например, на адресные структуры в сокетах: struct sockaddr, struct sockadd_in, struc sockaddr_in6. Это не самая удачная реализация, на мой взгляд, но достаточно распространенная. Гораздо лучше реализованы объекты в питоне (имею ввиду исходный код самого питона на Си), принцип тот же, но реализация более понятна.
callback может принимать указатель на заголовок структуры, затем его можно будет преобразовать в структуру для конкретного типа события. Хорошо бы для этого предусмотреть в реализации набор макросов.
Общий посыл таков: нужно как можно реже использовать void*, можно его использовать только тогда когда без этого ну вообще никак не обойтись (а если обойтись, то это будет ну очень "дорого"). К сожалению в Си время от времени приходится использовать void*. В т.ч. для решения этой проблемы в плюсах придумали шаблоны.

Я так и не понял, что означает type.
По моему идентифицировать издателей/подписчиков лучше всего по имени. И пусть имя они сами себе выбирают.

Где набор функций для добавления/удаления подписчиков?
Ответ написан
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Войти через центр авторизации
Похожие вопросы