Reputation: 73
Recently, I've made several attempts to understand the Bridge Pattern. Different websites are trying to explain this concept in different ways, but I'm beginning to understand this pattern - decouple abstraction and implementation - allows us to make different kinds of implementations, and additionally, we are able to extend our interface. But I just want to make sure with one thing - based on the example below:
#include <iostream>
class Device
{
protected:
int volume_m{ 0 };
public:
int getVolume()
{
return volume_m;
}
void setVolume(int value)
{
volume_m = value;
}
};
class RemoteController
{
private:
std::shared_ptr<Device> device_m;
public:
RemoteController(std::shared_ptr<Device> device) : device_m(device) {}
void volumeUp()
{
device_m->setVolume(device_m->getVolume()+10);
std::cout << "Volume turned up. Current volume: " << device_m->getVolume() << '\n';
}
void volumeDown()
{
this->device_m->setVolume(this->device_m->getVolume() - 10);
std::cout << "Volume turned down. Current volume: " << device_m->getVolume() << '\n';
}
};
class TV : public Device
{
};
class Radio : public Device
{
};
int main()
{
std::shared_ptr<Device> tv = std::make_shared<TV>();
std::shared_ptr<RemoteController> controller = std::make_shared<RemoteController>(tv);
controller->volumeUp();
controller->volumeUp();
controller->volumeUp();
}
What if I wanted to make different messages for TV
and Radio
? Should I make virtual methods in Device
called volumeUp()
and volumeDown()
which will be inherited by Radio
and TV
? And RemoteController
would only call these virtual methods?
Upvotes: 1
Views: 288
Reputation: 24738
Should I make virtual methods in
Device
calledvolumeUp()
andvolumeDown()
which will be inherited byRadio
andTV
? AndRemoteController
would only call these virtual methods?
Yes, in short, The Bridge Pattern uses delegation. RemoteController
delegates to the member functions defined by the Device
interface. TV
and Radio
can override Device
's virtual member functions.
The delegation is because The Bridge Pattern relies on composition. To understand why it does use composition, let's first see an example that doesn't take advantage of The Bridge Pattern.
You have two different types of devices: TV and radio. Let's assume that you have two different remote controllers: radio frequency and infrared controllers. Then, you would have four classes in total: RadioIRController
, RadioRFController
, TVIRController
, TVRFController
. These classes would implement an interface RemoteController
that specifies the virtual member functions volumeUp()
and volumeDown()
, i.e., a single hierarchy (i.e., RemoteController
).
In this design, if you now wanted to add a new kind of remote controller, for example, an ultrasonic controller, you would have to create two additional classes: RadioUSController
and TVUSController
. If you, in turn, wanted to add a new kind of device, for example, a home stereo system, you would then need to create three additional classes: HomeStereoIRController
, HomeStereoRFController
and HomeStereoUSController
.
As you can see, extending this design is tedious. This is because two orthogonal properties – the kind of device and remote controller – are mixed in a single class hierarchy. This is a strong motivation to switch to The Bridge Pattern.
You split the single hierarchy into two: Controller
and Device
. This way, each hierarchy can be extended independently to each other.
We've done so by partially switching away from inheritance, embracing composition, and relying on delegation: a RemoteController
refers to a Device
and calls the operations on this Device
object.
Extending this design for additionally supporting a home stereo system would only require to create a new class, HomeStereo
, which inherits from Device
. Likewise, extending this design for supporting an ultrasonic controller would just require the creation of a new class, USController
, which inherits from RemoteController
. You can now easily see the difference.
Upvotes: 0
Reputation: 32053
Yes, I believe that it will be more correct to implement VolumeUp
VolumeDown
methods in Radio
and TV
objects. Since they can potentially differ for these objects (not step 10 for both).
And I think that it’s better to try not to expose your implementation through getters and setters without much need. More about this here
Upvotes: 1