The bridge design pattern separates implementation from the interface of a program.
Why is this advantageous?
Software Engineering Stack Exchange is a question and answer site for professionals, academics, and students working within the systems development life cycle. It only takes a minute to sign up.Sign up to join this community
It allows you to change the implementation independently of the interface. This helps deal with changing requirements.
The classic example is replacing the storage implementation under an interface with something bigger, better, faster, smaller, or otherwise different without having to change the rest of the system.
In addition to Daniel's answer, separating interface from implementation through concepts like polymorphism allows you to create several implementations of the same interface that do similar things in different ways.
For example, lots of languages have a concept of a stream somewhere in the standard library. A stream is something that holds data for serial access. It has two basic operations: Read (load the next X number of bytes from the stream) and Write (add X number of bytes of data to the stream), and sometimes a third, Seek (reset the "current position" of the stream to a new location).
That's a simple enough concept, but think of all the things you could do with it. The most obvious one is to interact with files on disc. A file stream would let you read data from a file or write to it. But what if you wanted to send data over a network connection instead?
If you relied on implementations directly, you'd have to write out two completely different routines to save the same data to a file or to send it over the network. But if you have a stream interface, you can create two different implementations of it (
NetworkStream) that encapsulate the specific details of sending the data where it needs to go, and then you only need to write the code that deals with saving a file once. Suddenly your
SendOverNetwork routines are a lot simpler: they just set up a stream of the appropriate type and pass it to the
SaveData routine, which accepts a stream interface--it doesn't need to care what type, as long as it can perform the Write operation--and saves the data to the stream.
That also means that if your data format changes, you don't have to change it in multiple different places. If you centralize your data saving code in one routine that takes a stream, then that's the only place that it needs to be updated, so you can't accidentally introduce a bug by only changing one place when you needed to change both. So separating interfaces from implementations and using polymorphism makes for code that's simpler to read and understand, and that's less likely to have bugs.
You really have two very different questions here, though they are related.
The more general question is the one in the title, why would you separate interface from implementation in general. The second question is why the bridge pattern is useful. They are related because the bridge pattern is a specific way of separating interface from implementation, that has some specific other consequences as well.
The general question is something vital for every programmer to understand. It is what prevents changes in a program from propagating everywhere. I can't imagine humans being able to program without using this.
When you write a simple addition statement in a programming language, that is already an abstraction, (even if it isn't using operator overloading to add matrices or something like that) that goes through quite a lot of other code before it finally gets executed on a circuit in your computer. If there was no separation of the interface (say, "3+5"), from the implementation (a bunch of machine code), then you would have to change your code every time the implementation changed (like you wanted to run on a new processor).
Even within a simple CRUD application, every method signature is, in a broad sense, the interface to it's implementation.
All these kinds of abstraction have the same basic goal - have the calling code express it's intent in the most abstract possibly way that gives the implementer as much information as needed. That provides the minimal possible coupling between them, and limits the ripple effect when code needs to be changed as much as possible.
It sounds straightforward, but in practice it gets complicated.
The bridge pattern is a specific way of separating certain bits of implementation into interfaces. The class diagram of the pattern is more informative than the description. It's more like a way to have pluggable modules than a bridge, but they named it bridge because it's often used where the modules have been created prior to the interface. So creating a common interface for similar existing implementations sort of "bridges" the difference and allows you code to work with any of the implementations.
So, say you wanted to write an add-on to a word processor, but you want it to work on multiple word processors. You might create an interface that abstracts out the word processor based functionality you need (and which must be implementable by each word processor since you can't change those), and one implementer of that interface for each word processor you want to support. Then your application can call that interface and not worry about the details of each word processor.
It's actually slightly more detailed than that, because each class might really be a class hierarchy (so, there might not just be an abstract word processor, but an abstract Document, abstract TextSelection, etc., with concrete implementations for each), but it's the same idea.
It's a bit like a facade, except in this case the abstraction layer is focused on providing the same interface to multiple underlying systems.
It's related to Inversion Of Control, since the concrete implementer will be passed to methods or constructors and will determine the actual implementation called.