2016-04-08 3 views
0

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

Проблема: Два класса AudioStream10 и VideoStream получены из базового класса MediaStream, который имеет некоторые общие для аудио- и видеопотоков методы, но не предназначен для использования как есть. Следовательно, существуют два класса AudioStreamSettings и VideoStreamSettings, которые получены из MediaStreamSettings и переданы конструкторам соответствующих классов потоков. MediaStreamSettings сохраняет настройки, общие для аудио и видео, а базовый класс MediaStream обращается к этим данным. Вопрос в том, что было бы лучшим способом для разработки этой иерархической связи между базовыми классами потоков и настроек?

Я могу придумать быстрого решения, как следующее:

class MediaStream { 
public: 
    MediaStream(const MediaStreamSettings& settings){ 
    // do nothing, let derived classes initialize settings_ 
    // note: I feel guilty for doing this... 
    } 
    virtual ~MediaStream(){} 
protected: 
    std::shared_ptr<MediaStreamSettings> settings_; 
}; 

class VideoStream : public MediaStream { 
public: 
    VideoStream(const VideoStreamSettings& settings): 
    MediaStream(settings) 
    { 
    settings_ = std::make_shared<VideoStreamSettings>(settings); 
    } 

    void doSomething(){ 
    int s1 = std::dynamic_pointer_cast<VideoStream, MediaStream>(settings_)->getVideoStreamSetting1(); 
    ... 
    } 
}; 

class AudioStream : public MediaStream { 
public: 
    AudioStream(const AudioStreamSettings& settings): 
    MediaStream(settings) 
    { 
    settings_ = std::make_shared<AudioStreamSettings>(settings); 
    } 
} 

Резюмируя Я не комфортно с двумя вещами в этом подходе:

  1. не инициализирующих settings_ в базовом классе (следует Я делаю это абстрактным, чтобы успокоиться?)
  2. с использованием dynamic_pointer_cast каждый раз, когда мне нужно получить доступ к настройкам в производных классах (должен ли я сделать оболочку метода для этого?)
+0

Поскольку базовый класс предоставляет член данных 'settings_', он должен инициализировать этот элемент. Его конструктор должен затем принять аргумент, который либо предоставляет полный объект настроек напрямую, либо служит в качестве фабрики для его создания. Тем не менее, проблематичным здесь является потенциальное совместное использование настроек между несколькими объектами, созданными при копировании. Лучше сделайте этот «MediaStream» не скопированным. И тогда «unique_ptr» будет лучше подходит. –

+0

@ Cheersandhth.-Alf спасибо! во-первых, я на самом деле пытался использовать 'unique_ptr', но затем застрял с' dynamic_pointer_cast' для этого. Я согласен, 'shared_ptr' здесь не подходит. Я предполагаю, что комбинация «unique_ptr» и абстрактного метода, описанная в ответе @ Jarod42, будет лучшим дизайном – peetonn

ответ

1

Одним из решений является не хранить данные в MediaStream и добавить виртуальный метод

virtual const MediaStreamSettings& GetMediaStreamSettings() const = 0; 
+0

спасибо! Мне нравится этот подход. плюс, я попытаюсь использовать 'unique_ptr' вместо' shared_ptr' для 'settings_'. Некоторое время я буду держать вопрос открытым, чтобы люди дали больше альтернатив. – peetonn

1

Поскольку MediaStream не должны использоваться как есть, что делает его абстрактный класс должен быть приемлемым (и желательно). Таким образом, обеспечение реализации (включая членов класса) бессмысленно.

class IMediaStream { 
public: 
    virtual ~IMediaStream() {} 
    virtual void play() = 0; 
    virtual std::shared_ptr<MediaSettings> getSettings() = 0; 
private: 
    IMediaStream() {} 
}; 

template<Setting> 
class MediaStream : public IMediaStream { 
public: 
    MediaStream(const Setting& settings){ 
     settings_ = std::make_shared<Setting>(settings); 
    } 
    virtual ~MediaStream() {} 
    virtual void play() override { 
     // Implementation here 
    } 
    virtual std::shared_ptr<MediaSettings> getSettings() override { 
     return std::dynamic_pointer_cast<Setting, MediaSettings>(); 
    } 
private: 
    std::shared_ptr<Setting> settings_; 
} 

// Alternatively you can inherit or specialize 
// the template to add your implementation 
typedef MediaStream<VideoStreamSettings> VideoStream; 
typedef MediaStream<AudioStreamSettings> AudioStream; 
+0

спасибо! Наверное, мне нужно наследовать, поскольку «VideoStream» и «AudioStream» должны выполнять некоторые операции, специфичные для их типа. но использование шаблонов здесь - хорошая идея! Я буду считать, что – peetonn