Вступление:
Я родом из области машиностроения, но учился на программировании для встроенного программного обеспечения (на симпатичном маленьком роботе) с намерением улучшить некоторые навыки, которые у меня уже были в программировании. Тем не менее, класс был в значительной степени неудовлетворительным в том, что я надеялся достичь (в основном, он преподавал основы c ++ с некоторыми очень поверхностными композиционными шаблонами).
Вопрос Нам было сказано сделать наш код несколько объектно-ориентированным, определив классы для различных частей кода. Поскольку все части сильно зависели друг от друга, общая структура выглядела следующим образом (в основном класс Drive, Sensors и WorldModel с некоторыми зависимостями и класс Director, пытающийся заставить нашего робота решать поставленную задачу)
class Drive{
void update();
Drive(Sensors & sensors);
private:
Sensors & sensors
};
class Sensors{
void update();
}
class WorldModel {
void update();
WorldModel(Sensors & sensors, Drive & drive);
private:
Sensors & sensors;
Drive & drive;
};
class Director {
void update();
Director(Sensors & sensors, Drive & drive, WorldModel & worldmodel);
private:
Sensors & sensors;
Drive & drive;
WorldModel & worldmodel;
};
На самом деле это очень сжатая версия. Однако мне кажется, что это не столько объектно-ориентированный код, сколько Неуклюжий код раскола ™. В частности, казалось почти невозможным сделать, например, Sensors
класс получить данные из Drive
класс без некоторой суеты в Director
класс (т. е. сначала выполнить функцию в классе Drive, чтобы получить заданное значение скорости, а затем передать ее update()
метод в Sensors
класс, чтобы сделать некоторую фильтрацию Калмана).
Как создать проект в c ++ с различными частями, очень зависимыми друг от друга, не становясь при этом проблемой? Я прочитал ТАК ответ на интерфейсы но я не уверен, как применить это к этой проблеме — это даже путь сюда? Существует ли шаблон проектирования (не обязательно объектно-ориентированный), который подходит для таких проектов, как этот?
Нет, для таких проектов не существует шаблона проектирования.
Шаблоны дизайна не являются целью.
Итак, позвольте мне сформулировать несколько догадок:
Вот что я бы сделал:
храните нежелательные зависимости реализации от файла заголовка. При желании здесь можно использовать идиому Pimpl.
например если вы используете библиотеку X для реализации Y::frobnicate
не включать libX.h
в вашем Y.h
, Вместо этого, включите его в Y.cpp
только.
Если вы обнаружите, что вам нужно объявление члена класса, которое потребует libX.h
в заголовке используйте идиому Pimpl.
Я не знаю, что еще вы могли бы хотеть здесь 🙂
Возможно, если вам нужны «интерфейсы», подумайте об использовании композиции шаблона. Политика, стратегия, государственные модели. Например. Вместо
#include <set>
struct ISensors {
virtual int get(int id) const = 0;
virtual int set(int id, int newval) const = 0;
virtual std::set<int> sensors() const = 0;
};
class Drive {
void update();
Drive(ISensors &sensors);
private:
ISensors &sensors;
};
Вы могли бы рассмотреть
template <typename Sensors>
class Drive {
void update();
Drive(Sensors &sensors);
private:
Sensors &sensors;
};
Что оставляет вас свободным для реализации Sensors
любым способом, который статически компилируется. «Ограничением» является то, что внедрение зависимостей должен быть статически определен / напечатан. Преимущество заключается в максимальной гибкости и отсутствии накладных расходов: например, у вас не могло быть шаблонов виртуальных функций-членов, но вы можете использовать это как Sensors
Политика:
struct TestSensors {
int get(int) { return 9; }
int set(int, int) { return -9; }
template<typename OutputIterator>
OutputIterator sensors(OutputIterator out) const {
int available[] = { 7, 8, 13, 21 };
return std::copy(std::begin(available), std::end(available), out);
}
};
using TestDrive = Drive<TestSensors>;
Других решений пока нет …