LINUX.ORG.RU

Вопрос по структуру приложения

 ,


0

6

Добрый день, подскажите, пожалуйста, как лучше организовать общую структуру приложения. Что имеем: 1. Класс для работы с некой периферией (Class Periph) - занимается тем, что настраивает периферию и принимает с нее данные. 2. Класс для работы с данными полученными от периферии (Class DataParser). 3. Класс для логирования (Class Loging).

Принцип работы такой: пришли данные от периферии - мы их должны положить в очередь класса (DataParser). Потом в этом классе эти данные разбираются и т.д. Вопрос как лучше организовать передачу этих данных? Как-то находил пример подобного приложения, там было сделано так: каждый экземпляр класса был объявлен глобально, но по плюсам обычно крайне не рекомендуют использовать вообще глобальные переменные. Ну и опять же доступ к классу логирования, когда потребность записать лог может возникнуть в любом методе любого класса.

Класс для работы с некой периферией (Class Periph) - занимается тем, что настраивает периферию и принимает с нее данные.

Не один класс на всё, а по классу на тип периферийных устройств.

Класс для работы с данными полученными от периферии (Class DataParser)

Не класс для работы с данными, а отдельно свободные чистые функции для обработки данных, отдельно объекты агрегирующие данные.

Класс для логирования (Class Loging).

Возможно, но посмотри на существующие библиотеки логгирования (log4cplus, Boost.Log и др.).

Вопрос как лучше организовать передачу этих данных?

Через очереди :-) Каждый компонент получает ссылку на свой конец очереди и о том кто на другой стороне ничего не знает (и ему этого не надо). Тут можно посмотреть в сторону библиотек сигналов (QtCore, Boost.Signals2). У Qt сигналы работают между потоками, что может быть полезно.

Begemoth
()

1. Класс для работы с некой периферией (Class Periph) - занимается тем, что настраивает периферию и принимает с нее данные. 2. Класс для работы с данными полученными от периферии (Class DataParser).

Сразу два god object.

tailgunner
()
Ответ на: комментарий от Begemoth

если есть глобальные переменные?

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

no-such-file 👍👍👍👍👍
()
Ответ на: комментарий от matrixd

ну типо глобальные переменные в ооп не укладываются емнип

Это сродни утверждению, что по геттеру и сеттеру на каждое поле - ООП, а открытые поля - не ООП.

Begemoth
()
Ответ на: комментарий от matrixd

Ну можно обмазаться const

Здорово, а как ты будешь инициализировать свой константный указатель на объект в рантайме, если он константный?

no-such-file 👍👍👍👍👍
()

В самом простом случае один тупой цикл в главном потоке приложения. В этом цикле сначала снятие данных с устройства, затем обработка данных. Схематически это выглядит так:

int main() {
  logger_t log{ ... };
  peripheral_t device{ log, ... };
  parser_t parser{ log, ... };
  while( true ) {
    auto data = device.receive_data();
    parser.parse( data );
    ...
  }
}

Если этого недостаточно и нужно выносить работу с переферией и парсинг данных в разные потоки, то лучше использовать готовые фреймворки для организации многопоточного взаимодействия. Примитивы для этого можно найти в библиотеках ACE, POCO, C++ Actor Framework, SObjectizer, Intel TBB, Qt.

Для маленьких приложений C++ Actor Framework и SObjectizer применять будет проще всего.

Для логгирования хвалят библиотеку spdlog.

eao197 👍👍
()
Ответ на: комментарий от matrixd

Конструкторы и оператор присваивания - в private, либо как deleted (c++11)

А вообще singleton - это больше похоже на попытку притащить концепты из жабы в плюсы. В жапке глобальных переменных нет, вот и выкручиваются там костылями-синглтонами как могут, по сути симулируя именно глобальные переменные.

Это конечно мое мнение, но серьезных аргументов в пользу синглтона на плюсах я пока не слышал.

invy
()
Ответ на: комментарий от matrixd
Log::writeToDb << "entry";
Log::writeToStream << "entry;

где Log - namespace (для красоты), а writeToDb и writeToStream - глобальные объекты, по сути как cout/cerr;

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

  /**
   *  @name Standard Stream Objects
      ....
   */
  extern istream cin;           /// Linked to standard input
  extern ostream cout;          /// Linked to standard output
  extern ostream cerr;          /// Linked to standard error (unbuffered)
  extern ostream clog;          /// Linked to standard error (buffered)

И весь «синглтон» :)

invy
()
Последнее исправление: invy (всего исправлений: 3)
Ответ на: комментарий от invy

А вообще singleton - это больше похоже на попытку притащить концепты из жабы в плюсы.

Да легко что так.

Это конечно мое мнение, но серьезных аргументов в пользу синглтона на плюсах я пока не слышал.

Ну тут же кому что нравится.

matrixd
()
Ответ на: комментарий от invy

А вообще singleton - это больше похоже на попытку притащить концепты из жабы в плюсы.

Отнюдь. Singleton - это средство от «static initialization order fiasco»

annulen 👍👍👍👍👍
()
Ответ на: комментарий от annulen

Хмм, а такой вариант:

template<typename T>
class delay_init
{
public:

  auto operator*() -> T& 
  {  
    if (!val) val = std::make_unique<T>();
    return *T;
  }

private:
   std::unique_ptr<T> val;
};

не решение? потокобезопасность, константность и произвольные аргументы конструктора добавляются без проблем (и std::unique_ptr можно заменить на boost::optional или будущий std::optional). При этом получаем переиспользуемый класс для отложенной инициализации, а не только идиому синглтонов.

Begemoth
()
Последнее исправление: Begemoth (всего исправлений: 1)
Ответ на: комментарий от annulen

Singleton - это средство от «static initialization order fiasco»

Или замена его на «dynamic initialization order fiasco»

tailgunner
()
Ответ на: комментарий от invy

В синглтоне тоже перегружать надо

Лол что? С синглтоном ты работаешь через методы-аксессоры. Нет ну если тебе припекает непременно сделать лишнюю работу, то можно конечно и прикрутить перегруженные операторы, но нахрена?

no-such-file 👍👍👍👍👍
()
Ответ на: комментарий от Begemoth

Костылять?

Но ведь объект уже имеет аксессоры для доступа к элементам, а операторы нужно ещё накостылять, причём всё равно тебе придётся внутри них придумывать синглтон, только через жопу, т.е. вместо того, чтобы поместить конструктор в private, ты будешь руками писать код, который запретит использовать объект данного типа в lvalue. omfg Ты не забыл зачем всё это вообще делается, что это не ради олимпиады на лоре? Твои же коллеги набьют тебе морду, как только им придётся разбираться в этом говнище.

no-such-file 👍👍👍👍👍
()
Ответ на: комментарий от invy

больше похоже на попытку притащить концепты из жабы в плюсы

И что в этом плохого? Слишком просто, а не через задницу и нет шаблонов на шаблонах в шаблонах?

но серьезных аргументов в пользу синглтона

Синглтон надёжнее, чем глобальная переменная, т.к. даёт гарантию, что его нигде не подменяют и не портят в т.ч. в той части кода, которую писал не ты, а Вася из соседнего отдела.

на плюсах

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

no-such-file 👍👍👍👍👍
()
Ответ на: комментарий от no-such-file

Ты дурак? Так и должно быть, ради этого всё и делается.


Синглтон надёжнее, чем глобальная переменная, т.к. даёт гарантию, что его нигде не подменяют и не портят в т.ч. в той части кода, которую писал не ты, а Вася из соседнего отдела.

Слив засчитан.

invy
()
Последнее исправление: invy (всего исправлений: 2)
Ответ на: комментарий от invy
  A x = A::getInstance(); // fail...

смотря что там твой этот метод вернет.

A *x = A::getInstance();
Вполне прокатит

  A::getInstance() = A(); // epic fail...

Это вообще трэш. Ты либо думай как делать проверку не создается ли объект повторно, либо прячь конструктор. В любом случаи эти ошибки в процессе компиляции обнаружатся.

matrixd
()
Ответ на: комментарий от invy

Слив засчитан

Так ты даже русским не владеешь и не можешь донести свою мысль до собеседника. Нормальные люди как бы подразумевают, что в синглтоне

 T(T const&);
 void operator=(T const&);
спрятано в private - тут никакой дополнительной работы (писать реализацию) делать не надо.

no-such-file 👍👍👍👍👍
()
Ответ на: комментарий от no-such-file

спрятано в private

В новом коде уже пишут «= delete».

anonymous
()

Ого) Столько ответов) Спасибо за пайтон, лисп и т.п но это встраиваемая система, по этой же причине либы для логирования пролетают. Вариант с асмом подходит, но тоже нет, спасибо) Но что-то как-то по существу ответов и не было:(

hell_wood
() автор топика
Ответ на: комментарий от hell_wood

1. QSerialPort 2. TheMyDataParseClass (слушает события QSerialPort) 3. qDebug()

но это встраиваемая система

встраиваемые системы разные бывают, если не потянет qt, перепеши на свои велосипеды

anonymous
()
Ответ на: комментарий от invy

что у тебя аргументы кончились

Ну ок, я понял, что ты не хочешь продолжать разговор, предпочитая пукать в лужу. Ну давай, до свиданья.

no-such-file 👍👍👍👍👍
()
Ответ на: комментарий от anonymous

Сигналы-события да интересно, но как быть с многопоточностью (тут вопрос да не в стороне embedded ). Например Class Periph принимает данные в одном потоке, а Class DataParse должен разбирать данные в другом потоке. Если брать qt то там все сигналы на сколько я знаю в главном потоке обрабатываются.

hell_wood
() автор топика

IoC в С++

Вот я запустил тред, там меня все обсирали. А в этом треде такие же плюсовики советуют кучу гадостей и спорят.

vertexua
()

Почитай Dependency Injection и умоляю, не слушай грамотеев из этого треда, которые вылезли из пещер и советуют всякие синглтоны вроде MyClass::GetInstance(), это просто фантастически бездарно и тупо.

vertexua
()
Последнее исправление: vertexua (всего исправлений: 1)
Ответ на: комментарий от invy

В жабке такие проблемы как в плюсах все обсуждали в 1995 году. За вот такой синлтон как ты тут советуеш могут отрубить руки

vertexua
()

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

Не хочешь — не используй. Алсо «не рекомендуется» — еще не значит «ты не сможешь выстрелить себе в ногуесли захочешь»

slackwarrior 😊😊😊
()
Ответ на: комментарий от eao197

ACE, POCO, C++ Actor Framework, SObjectizer, Intel TBB, Qt

Какая ненавязчивая самореклама :)

Для маленьких приложений

std::thread не, если уж сказали auto? Может и доп. зависимости не понадобятся. От слова вообще.

slackwarrior 😊😊😊
()
Ответ на: комментарий от vertexua

Могут хотеть отрубить руки :) Ну и... могут продолжать хотеть :)

slackwarrior 😊😊😊
()
Последнее исправление: slackwarrior (всего исправлений: 1)
Ответ на: комментарий от no-such-file

Я сказал что для синглтона тоже надо перегружать операторы. Ты понес какой-то бред, а потом сам таки признался, что:

 T(T const&);
 void operator=(T const&);

invy
()
Ответ на: комментарий от no-such-file

наверное, мсье имеет в виду лейзи лоад при первом вызове геттера инстанца, который подобных телодвижений не требует вообще :)

slackwarrior 😊😊😊
()
Ответ на: комментарий от no-such-file

В шаблоне не надо писать реализацию... Спасибо, кэп. Но и инициализацию снаружи делать не обязательно :)

slackwarrior 😊😊😊
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.