Bridge Design Pattern in Modern C++
Bridge Design Pattern in Modern C++
Bridge Design Pattern is a Structural Design Pattern used to decouple a class into two parts so that both can be developed independently.
Join the DZone community and get the full member experience.Join For Free
Bridge Design Pattern is a Structural Design Pattern used to decouple a class into two parts — abstraction and it's implementation — so that both can be developed independently. This promotes the loose coupling between class abstraction and its implementation. You get this decoupling by adding one more level of indirection i.e. an interface that acts as a bridge between your original class and functionality. Insulation is another name of the Bridge Design Pattern in the C++ world.
"All problems in computer science can be solved by another level of indirection." — David Wheeler
The code snippets you see throughout this series of articles are simplified not sophisticated. So you often see me not using keywords like
public(while inheritance) just to make code compact and consumable(most of the time) in a single standard screen size.
I also prefer
struct instead of
class just to save line by not writing "
public:" sometimes and also miss virtual destructor, constructor, copy constructor, prefix
std::, deleting dynamic memory, intentionally. I also consider myself a pragmatic person who wants to convey an idea in the simplest way possible rather than the standard way or using Jargon.
- If you stumbled here directly, then I would suggest you go through What is a design pattern? first, even if it is trivial. I believe it will encourage you to explore more on this topic.
- All of this code you encounter in this series of articles are compiled using C++20(though I have used Modern C++ features up to C++17 in most cases). So if you don't have access to the latest compiler you can use https://wandbox.org/ which has preinstalled boost library as well.
To separate the interface from its implementation.
- In other words, It's all about connecting components together through flexible abstractions using aggregation/composition rather than inheritance/generalization.
- This pattern involves an interface that acts as a bridge. That makes the functionality of concrete classes independent from interface implementer classes. Both types of classes can alter structurally without affecting each other.
The Motivation for Bridge Design Pattern
- Bridge Design Pattern prevents the Cartesian Product complexity explosion. Don't be scared with this mathematical term, I have simplified it with an example below.
- So, for example, let's suppose that you have some base class called
Shapeand then the
Squareand it can also be drawn by API 1 or API 2.
- This way you end up having a two by two(2×2) scenario. So if you decide to implement it you have to implement four classes. One for you know the
API_2and so on.
- The Bridge Design Pattern is precisely the pattern that avoids this whole entity explosion.
- So instead of having something like above, what we can do is we design the DrawingAPI interface(which later on used to derive API 1 and 2) and aggregate it in
- So the following is the typical implementation of the Bridge Design Pattern. We are not going to look at anything quite so complicated here. But essentially a bridge is a mechanism that decouples the interface or the hierarchy from the implementation.
- This way you don't rely as much as on inheritance and aggregation. Rather you rely on the interface.
- How can we forget the PIMPLE idiom while we are discussing the Bridge Design Pattern! PIMPLE is the manifestation of the bridge design pattern albeit a slightly different one.
- PIMPL idiom is all about hiding the implementation details of a particular class by sticking it into separate implementation pointed by pointer just as the name suggests. Let me show you how this works:
Person.cpp <— will be turned into a shared library(.so/.dll), to hide the business logic
- OK, so this is the pimple idiom in it's kind of concise form shall we say. And the question is Well why would you want to do this in the first place.
- Security purpose, you might have a question that any way we are going to expose a header file to the client which contains the API of a class, then how do we get security here? Well, just think about the data members and private methods. If you have trade secrets and having a data member which contains critical information. Why do you even let the client know the name of the object?
- One more benefit of PIMPL is compilation time which is critical for C++ as it is widely criticized for it. But this is becoming less and less relevant as the compilers become more and more incremental. And they are fantastic nowadays.
- As we have to use all the API using indirection provided by std::unique_ptr which accounts for some run-time overhead as we have to dereference the pointer every time for access.
- Plus we also have construction and destruction overhead of std::unique_ptr because it creates a memory in a heap which involves many other functions calling along with system calls.
- Moreover, we also have to bear some indirection if we want to access the data member of
thispointer or so.
Person.cpp <— Will be turned into a shared library(.so/.dll), to hide the business logic
- So let's address this issue with the placement new operator and preallocated aligned memory buffer. reinterpret_cast is just a compile-time substitute so there won't be any other indirection.
- Bridge Design Pattern provides flexibility to develop abstraction(i.e. interface) and the implementation independently. And the client/API-user code can access only the abstraction part without being concerned about the Implementation part.
- It preserves the Open-Closed Principle, in other words, improves extensibility as client/API-user code relies on abstraction only so implementation can modify or augmented any time.
- By using the Bridge Design Pattern in the form of PIMPL. We can hide the implementation details from the client as we did in the PIMPL idiom example above.
- The Bridge Design Pattern is an application of the old advice, "prefer composition over inheritance" but more smartly. It comes handy when you must subclass different times in ways that are orthogonal with one another(say 2×2 problem discuss earlier).
- A compile-time binding between an abstraction and its implementation should be avoided. So that an implementation can select at run-time.
What is the practical use case of the Bridge Design Pattern?
Plugins in any internet browser leverage this pattern directly where the browser specifies only abstraction and implementation varies by different types of plugins.
When to use Bridge Design Pattern?
— When you are unsure of implementation or its variations and still you want to move forward with development.
— In case of a behavior permutation problem i.e. Cartesian Product Complexity Explosion.
What are the differences between the Adapter and Bridge Design Pattern?
— The adapter is commonly used with an existing app to make some otherwise-incompatible classes work together nicely.
— The bridge is usually designed up-front, letting you develop parts of an application independently of each other.
What are the differences between Strategy and Bridge Design Pattern?
— The strategy is a single dimension problem like a Multi-bit screwdriver.
— The bridge is a multi-dimension problem like communication types and devices.
Published at DZone with permission of Vishal Chovatiya . See the original article here.
Opinions expressed by DZone contributors are their own.