The three design patterns (Adapter, Facade and Bridge) all produce the result of a clean public API. The difference between the patterns are usually due to a subtle context shift (and in some cases, a behavioural requirement).
The primary function of an Adapter is to produce a unified interface for a number of underlying and unrelated objects.
You will notice this pattern being utilised in many applications. For example, ActiveRecord (the popular Ruby ORM; object-relational mapping) creates a unified interface as part of its API but the code underneath the interface is able to communicate with many different types of databases. Allowing the consumer of the API to not have to worry about specific database implementation details.
The principle structure of this pattern is:
Current | Future
----------------
B(C) | B(A)
The B
function cannot be changed and it is dependant on the interface that was originally provided by C
, but now we are passing in A
which has an incompatible interface.
An adapter can solve this by creating a new function A2C
which contains the relevant logic for handling the interaction between B
and A
.
Current | Future
----------------
B(C) | B(A2C(A))
The primary function of a Facade is to simplify the interaction between a consumer and an interface.
Most DSL's are a facade of some form. The popular jQuery library consists of multiple facades (one for each type of feature). For example, the jQuery ajax
method makes it very easy to make an XHR (XMLHttpRequest
).
The difference between a Facade and an Adapter is that the Facade makes a simple abstraction, where as an Adapter will handle complex interactions by taking incoming data and constructing it to work with the underlying objects.
The primary function of a Bridge is to decouple an abstraction from its implementation.
Adapter makes things work after they're designed
Bridge makes them work before they are
Imagine you have a function that abstracts the implementation detail of making an HTTP request to an external API endpoint. In a language like JavaScript you might tightly couple the abstraction with the consumer code.
For example:
function get(e) {
return asyncRequest('foo?bar=' + this.id, function(response) {
console.log(response)
})
}
myTrigger.addEventListener('click', get, false)
The above abstraction (i.e. the get
function) will only ever work within the context of a web browser. The abstraction has been tightly coupled to the consumer.
Utilising a bridge will allow us to decouple this code:
function get(id, callback) {
return asyncRequest('foo?bar=' + id, function(response) {
callback(response)
})
}
function getBridge(e) {
get(this.id, function(response) {
console.log(response)
})
}
myTrigger.addEventListener('click', getBridge, false)
Information was collated from different sources such as "Pro JS Design Patterns", rubybestpractices.com and agileevidence.com