2

Bridge design pattern is something which is very confusing and GOF does not do justice with beginners in the definition.

I was asked in my current organisation to add one more dimension to our class and use Bridge pattern for it, knowing nothing about it I went through some blogs and have implemented the same for our code. OFC I cannot paste the code base here so providing some minimal similar example as that in my code base.

Say there is a video class containing 2 dimension: VideoType and VideoProcessor. These 2 dimensions are independent of each other. And without using the bridge design pattern, this is what the code would have looked like.

#include <iostream>

class Video
{
    protected:
    std::string filename;
    public:
    Video(const std::string &filename)
    {
        this->filename = filename;
    }
    virtual void ProcessVideo() = 0;
    virtual void Play() = 0;
};

class NetflixVideoHD : public Video
{
    public:
    NetflixVideoHD(const std::string &filename) : Video(filename) {    }

    void Play()
    {
        std::cout<<"Playing HD Netflix video : " << filename << std::endl;
    }

    void ProcessVideo()
    {
        std::cout<<"Processing HD Netflix video : " << filename << std::endl;
    }
};

class NetflixVideo4KHD : public Video
{
    public:
    NetflixVideo4KHD(const std::string &filename) : Video(filename) {    }

    void Play()
    {
        std::cout<<"Playing 4KHD Netflix video : " << filename << std::endl;
    }

    void ProcessVideo()
    {
        std::cout<<"Processing 4KHD Netflix video : " << filename << std::endl;
    }
};

class YouTubeHD : public Video
{
    public:
    YouTubeHD(const std::string &filename) : Video(filename) {    }

    void Play()
    {
        std::cout<<"Playing HD YouTube video : " << filename << std::endl;
    }

    void ProcessVideo()
    {
        std::cout<<"Processing HD YouTube video : " << filename << std::endl;
    }
};

class YouTube4K : public Video
{
    public:
    YouTube4K(const std::string &filename) : Video(filename) {    }

    void Play()
    {
        std::cout<<"Playing 4K YouTube video : " << filename << std::endl;
    }

    void ProcessVideo()
    {
        std::cout<<"Processing 4K YouTube video : " << filename << std::endl;
    }
};

int main()
{
    Video *nethd = new NetflixVideoHD("Video.mp4");
    Video *net4khd = new NetflixVideo4KHD("Video.mp4");
    Video *ythd = new YouTubeHD("Video.mp4");
    Video *yt4Khd = new YouTube4K("Video.mp4");

    nethd->ProcessVideo();
    nethd->Play();

    net4khd->ProcessVideo();
    net4khd->Play();

    ythd->ProcessVideo();
    ythd->Play();

    yt4Khd->ProcessVideo();
    yt4Khd->Play();

    delete nethd;
    delete net4khd;
    delete ythd;
    delete yt4Khd;
}

Now after converting the same to bridge design pattern by converting one base class to abstract and other to interface, this is how the new code looks like.

#include <iostream>

/* One dimension converted to Interface */
class VideoProcessorInterface
{
    public:
    virtual void ProcessVideo(const std::string &filename) = 0;
};

class VideoProcessorHD : public VideoProcessorInterface
{
    public: 
    void ProcessVideo(const std::string &filename)
    {
        std::cout<<"Processing HD video : " << filename << std::endl;
    }
};

class VideoProcessor4KHD : public VideoProcessorInterface
{
    public:
    void ProcessVideo(const std::string &filename)
    {
        std::cout<<"Processing 4K video : " << filename << std::endl;
    }
};

/* Other dimesnion used as abstract class */
class Video
{
    protected:
    std::string filename;
    VideoProcessorInterface *videoProcessor;
 
    public:
    Video(const std::string &filename, VideoProcessorInterface *videoProcessor)
    {
        this->filename = filename;
        this->videoProcessor = videoProcessor;
    }

    virtual void ProcessVideo() = 0;
    virtual void Play() = 0;
};

class NetflixVideo : public Video
{
    public:
    NetflixVideo(const std::string &filename, VideoProcessorInterface *videoProcessor) : Video(filename, videoProcessor) {    }

    void Play()
    {
        std::cout<<"Playing Netflix video : " << filename << std::endl;
    }

    void ProcessVideo()
    {
        std::cout<<"Processing Netflix video in below quality " << filename << std::endl;
        videoProcessor->ProcessVideo(filename);
    }
};

class YouTube : public Video
{
    public:
    YouTube(const std::string &filename, VideoProcessorInterface *videoProcessor) : Video(filename, videoProcessor) {    }

    void Play()
    {
        std::cout<<"Playing YouTube video : " << filename << std::endl;
    }

    void ProcessVideo()
    {
        std::cout<<"Processing YouTube video in below quality " << filename << std::endl;
        videoProcessor->ProcessVideo(filename);
    }
};



int main()
{
    VideoProcessorHD hdVideoProcessor;
    VideoProcessor4KHD f4KVideoProcessor;

    Video *nethd = new NetflixVideo("Video.mp4", &hdVideoProcessor);
    Video *net4khd = new NetflixVideo("Video.mp4", &f4KVideoProcessor);
    Video *ythd = new YouTube("Video.mp4", &hdVideoProcessor);
    Video *yt4Khd = new YouTube("Video.mp4", &f4KVideoProcessor);

    nethd->ProcessVideo();
    nethd->Play();

    net4khd->ProcessVideo();
    net4khd->Play();

    ythd->ProcessVideo();
    ythd->Play();

    yt4Khd->ProcessVideo();
    yt4Khd->Play();

    delete nethd;
    delete net4khd;
    delete ythd;
    delete yt4Khd;
}

I just wanted to know whether the above conversion strategy follows bridge design pattern. And what are the issues with it.

1 Answer 1

0

I just wanted to know whether the above conversion strategy follows bridge design pattern

Structurally, it is equal to the Bridge pattern, but semantically, I would classify this more as Strategy pattern, which is structurally the same. We talk of a Strategy when a behavioural abstraction gets its own interface and can be switched at runtime - and video processing looks very much like a behaviour for me. But don't mind, I would not be astonished if that is what the one who asked you to introduce the Bridge pattern had in mind.

what are the issues with it

The first thing I would always ask when introducing any kind of pattern is:

  • Is this really necessary or does it overcomplicates things?

In case of a video processor, I can imagine of implementations for HD and 4KHD processing which are sufficiently different to justify different classes for them. Still, if we assume for a moment that both implementations are identical, and both classes only differ by some default resolutions, you may consider not to create a class hierarchy and use just a VideoProcessor object with the required resolution as a constructor parameter.

Still, you will have to look at the real case, not at some contrived example to make a sensible decision.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.