简体   繁体   中英

Design pattern: inheritance and encapsulated inheritance

I got problems formulating it precisely so I left more general description in the title (if you have more precise description of the problem, please comment, I'll edit the title).

The problem: Two classes AudioStream and VideoStream are derived from base class MediaStream which has some common for audio and video stream methods, but is not intended to be used as-is. Consequently, there are two classes AudioStreamSettings and VideoStreamSettings which are derived from MediaStreamSettings and passed to the constructors of their corresponding stream classes. MediaStreamSettings stores settings common for audio and video, and base class MediaStream accesses this data. The question is: what would be the best way to design this hierarchical relationship between base classes of streams and settings?

I can think of a quick solution like the following:

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);
  }
}

To summarize I'm not comfortable with two things in this approach:

  1. not initializing settings_ in base class (should I make it abstract to calm myself?)
  2. using dynamic_pointer_cast every time I need to access settings in derived classes (should I make a method wrapper for this?)

一种解决方案是不将数据存储在MediaStream并添加虚拟方法

virtual const MediaStreamSettings& GetMediaStreamSettings() const = 0;

Since MediaStream should not be used as-is, making it an abstract class should be acceptable (and desirable). Thus providing implementation (which includes class members) is pointless.

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;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM