C ++ дизайн и полиморфизм - PullRequest
0 голосов
/ 16 мая 2018

У меня есть общий вопрос о дизайне класса 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 не нужна контрольная сумма, ему даже не нужно вызывать calcCheckSum () или если ему нужны некоторые дополнительные функции, нам не нужно добавлять его ко всем генераторам типов.

Но Подход 2 более читабелен, поскольку все типы делают вещи одинаково.

1 Ответ

0 голосов
/ 16 мая 2018

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

Каждый класс отвечает за одну вещь.

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

Правка: Обратите внимание, это все еще выглядит немного неуклюжим, ноэто больше относится к обмену стеками просмотра кода , где вы можете получить подробную информацию о вашей структуре.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...