Здравствуйте. Пишу софт для встраиваемых систем.Начал переходить с Си на Си++. Разработывая библиотеки на с++ я заметил, что часть кода в каждой из моих библиотек повторяется, а именно часть привязки каждой библиотеки к общей энергнезависимой памяти и энергозависомй памяти доступной из вне. В итоге формируется общая таблица данных доступных по протоколу ModBus и тд.
Таким образом добавляя ту или иную библиотеку в проект ее данные становятся доступными для изменения и считывания по ModBus.
Вопрос в следующем, как лучше организовать код, чтобы не нужно было писать одинаковый код для каждой новой библиотеки?
Я начал с создания базового класса для всех библиотек в котором описаны общие для всех библиотек функции, а каждая из библиотек наследуя базовый описывает свои особенные виртуальные методы. У меня получилось, что все созданные объекты любого унаследованного от базового класса становятся в общую очередь, в которой происходит вызов их виртуальных функций в Main.
Однако я чувствую, что поступаю неверно и есть способ лучше. Подскажите, как лучше реализовать данную задачу?
Вопрос в следующем, как лучше организовать код, чтобы не нужно было писать одинаковый код для каждой новой библиотеки?
Вариантов проектирования, как правило, бывает множество. Учитывая, что используется С++, желательно использовать некоторые "правила хорошего тона" ООП. В вашем случае - "разделение ответственности". Как я понял из постановки вопроса - "привязка" не есть основная задача библиотек. Так вынесите этот функционал в отдельный класс (например паттерн "фабрика"). Если "привязка" - функционал глобальный, имеет смысл использовать паттерн "синглтон".
В свое время экспериментировал с подобным, написал пробный пример "фабрика синглтонов". Посмотрите, возможно найдете для себя что-то полезное. В крайнем случае - не найдете)
#include <iostream>
#include <memory>
////////////////////////////////////////////////////////////////////////////////////////
template<typename T>
struct Holder {
Holder() {
std::cout << "Holder()::Holder()" << std::endl;
if (!Self) Self = new T();
Self->Init();
}
~Holder() {
if (Self) {
Self->Cleanup();
delete Self;
std::cout << "~Holder()::Holder()" << std::endl;
}
}
T* Self = nullptr;
};
////////////////////////////////////////////////////////////////////////////////////////
template <typename T>
class Singleton {
public:
static T* Instance() {
std::cout << "Singlton::Instance()" << std::endl;
static Holder<T> Dummy;
return Dummy.Self;
}
private:
Singleton() = delete;
Singleton(Singleton const&) = delete;
Singleton& operator= (Singleton const&) = delete;
Singleton(Singleton const&&) = delete;
Singleton& operator= (Singleton const&&) = delete;
};
////////////////////////////////////////////////////////////////////////////////////////
class Base {
public:
virtual void Init() { std::cout << "Base::Init()" << std::endl; }
virtual void Cleanup() { std::cout << "Base::Cleanup()" << std::endl; }
};
////////////////////////////////////////////////////////////////////////////////////////
class Config: public Base {
public:
int i = 0;
void Init() override { std::cout << "Config::Init()" << std::endl; }
};
////////////////////////////////////////////////////////////////////////////////////////
class ConfigDerived: public Config {
public:
int j = 0;
void Cleanup() override { std::cout << "ConfigDerived::Cleanup()" << std::endl; }
};
////////////////////////////////////////////////////////////////////////////////////////
int main() {
std::cout << "===================================" << std::endl;
auto R1 = Singleton<Config>::Instance();
auto R2 = Singleton<ConfigDerived>::Instance();
std::cout << "R1->i: " << R1->i << std::endl;
R1->i = 7;
std::cout << "R2->i: " << R2->i << std::endl;
std::cout << "===================================" << std::endl;
R2->i = 3;
auto XX = Singleton<ConfigDerived>::Instance();
std::cout << "XX->i: " << XX->i << std::endl;
std::cout << "===================================" << std::endl;
return 0;
}
Фактически ты пишешь сво собственный API, это возможный вариант.
В принципе есть три выхода:
Как ни странно звучит последний вариант, на самом деле он достаточно часто встречается. в различном банковском и промышленном ПО.
Айфон мало держит заряд, разбираемся с проблемой вместе с AppLab
Перевод документов на английский язык: Важность и ключевые аспекты
Какие существуют виды рекламных бордов и как выбрать подходящий?
Доброго времени сутокПокопал много страницы учебников/интернета, но так и ничего не нашёл
Здравствуйте, я пытаюсь воспроизвести похожее на list из библиотеки stl
Как написать оператор *= для длинных беззнаковых чисел методом умножения в столбик (длинная арифметика) без использования оператора *, если...