У меня общий вопрос по дизайну классов C++. Например, мне нужен генератор пакетов. Итак, учитывая тип пакета, я должен сгенерировать пакет этого типа. Итак, у меня есть базовый класс генератора пакетов.
Подход 1:
class BasePacketGenerator {
public:
virtual Packet* generatePacket (int type); // implements the generic case
// hence not pure virtual
protected:
//
// Common functionality for all types
//
virtual void massagePacket (Packet& pkt); // called by generatePacket
// but needs special handling for
// some types
virtual void calculateCheckSum(Packet& pkt); // called by generate packet
...
};
Производные классы для обработки каждого типа:
class Type1PacketGenerator : public BasePacketGenerator {
public:
// Dont have to override any base class implementationa
protected:
void calculateCheckSum(Packet& pkt) override;
};
class Type2PacketGenerator : public BasePacketGenerator {
public:
Packet* generatePacket(int type) override;
};
Здесь для генератора Type1 мы используем полиморфизм. Но вызовы базового класса, функциональность производного класса полиморфно. Интересно, хорошая ли это идиома? Или должен быть промежуточный класс
Подход 2:
class TypeHandler {
virtual Packet* setupPacket();
virtual void calculateCheckSum(Packet& pkt);
virtual void setupFields (Packet& pkt);
}
class PacketGenerator {
public:
TypeHandler *handler_; // lets say this is setup based on the type
Packet* generatorPacket(int type)
{
auto packet = handler_->setupPacket();
handler_->massagePacket();
handler_->calculateCheckSum(*packet);
return packet;
}
}
Есть ли какое-то преимущество в использовании того или иного подхода?
Подход 1 более гибкий, поскольку он не должен следовать одному и тому же образу действий. Например: если Type2Generator не нуждается в контрольной сумме, ему даже не нужно вызывать calculateCheckSum () или, если ему нужны дополнительные функции, нам не нужно добавлять его ко всем генераторам типов.
Но подход 2 более читабелен, поскольку все типы делают то же самое.
Я считаю, что ваш второй пример касается темы разработки на основе политик - en.wikipedia.org/wiki/Policy-based_design. Хорошо сочетается с шаблонами.
Ответ на ваш вопрос очень зависит от разных факторов. Дизайн класса должен учитывать многие аспекты предметной области и проблемы. Например, почему вы не можете реализовать «простейший» дизайн полиморфизма? Пример здесь. Интерфейс packet и разные реализации для каждого типа.
@BiagioFesta: это похоже на мой подход 2, за исключением того, что он использует чистый класс интерфейса. Я попытаюсь понять, смогу ли я создать интерфейсный класс и как бы абстрагировать общие функции для другого класса.





Чувствительность современного дизайна склонна к очень агрессивному разделению проблем. Таким образом, это приводит к предпочтению базовых классов, которые представляют собой не что иное, как объявления чистых виртуальных функций.
Каждый класс отвечает за 1 вещь.
Таким образом, ваш второй подход считается гораздо более предпочтительным. Основная причина (и единственная, которая вам действительно нужна) заключается в том, что это значительно упрощает написание надлежащих модульных тестов.
Редактировать: заметьте, это все еще выглядит немного неуклюже, но это больше вопрос Обмен стека codereview, где вы можете получить подробный отзыв о своей структуре.
Спасибо за ответ. по поводу base classes that are nothing but pure virtual function declarations. Этого можно достичь, если я перенесу все общие функции в другой класс, и каждый обработчик типов просто будет ссылаться на него, я думаю.
Похоже на заводскую выкройку?