The slides from my course in software architecture hints that these are seperate terms, but I can't seem to find the difference. Aren't all of them just translating interfaces?
It was very common for early patterns research to put a lot of emphasis on the "intended use" of a pattern, over and above any structural differences in the implementation. Then, people who were at that stage of architectural maturity where they were "doing patterns because patterns is what you do" developed long, often elaborate explanations on why these alleged differences were important.
However, research has shown that the structure is really all that matters, because the semantic distinctions:
- have no formal distinctions, even in the mathematical treatment of type theory
- are not enforceable without syntactic differences in developing the type relations (compiler needs something to enforce)
- therefore change with changing requirements
- and should not be forced not to change, as reuse is the point of good architecture
So much of those large discussions on why strategy is different than state have turned out quite labored, unconvincing, ineffectual, and slightly humorous as the years have moved on.
My suggestion is to ignore any "is used for" discussion at all and completely focus on the type relationships. If you do that, then you will find that (depending on your particular definition of these patterns, but fairly standard here)
Mediator > Bridge > Adapter
where the > relation should be read as "is implemented using". Adapter is a functional relationship between three or more types around on one abstraction tree. Bridge and Mediator are functional relationship between four or more types around two abstraction trees, defining an interface between the abstraction trees. Mediator adds to the type coupling usage relationships between concrete nodes of the abstraction trees.
Typically, Mediator is a bad pattern (antipattern) that doesn't scale well and causes an application to become monolithic. It is used very frequently because people read what it does and go "oh, I need that" and use a pattern becasue, as above, well, patterns are "what you use". They may be an intermediate step while decoupling a heavily coupled application during refactoring, but typically if you are making that step, full decouple to Bridge (with a factory) is indicated and just as easy.
Generally there are a lot of notions of interfaces in computer science. You should probably say that you are talking about about design patterns. In the corresponding Wikipedia article, there is a classification of different patterns that clears things up:
The other two are structural (actually comparing interfaces):
the wrapper/adapter pattern is focused on making an interface compatible, for example if a client uses different conventions;
the bridge pattern is about separating what the class is supposed to do (abstraction) from how it actually does it (implementation). That way you can use the abstraction without knowing how it is implemented, which is useful when the code changes (for both sides).
There are differences. Most of them are subtle enough that you wouldn't care, but they generally differ either in intent or in implementation. The overarching idea is to provide class A with access to the functionality of class B, without A having to care that it's B doing the work (so that a class C can be substituted without any of these objects having to change). This idea is typically called "loose coupling" and is generally to be encouraged..
A Bridge is the most basic definition of the intent to decouple A and B; that, in and of itself, is the purpose. A instead knows about an interface I, which B implements. A class C can also implement I and can be substituted freely.
A "wrapper" or Adapter is typically written with the intention of changing the interface of B to match the set of functionality that A expects of its dependency I. If A expects I to have a "DoThis()" method with three parameters, but the method with the functionality A needs on B is actually named "DoThat()" and takes a parameter, an Adapter W can be written that is dependent on B (or B's interface IB), implements I, and calls B.DoThat() from its own DoThis() method (passing the parameter, which it can gain without A's knowledge). If C is needed instead and differs from B, a different Adapter W2 can be written which takes a C and also implements I, so A, W, I, B, and C don't have to change.
Mediator patterns are basically an Adapter used as a Bridge. A Mediator is its own object M, which knows about B and is given to A. When A calls methods on M, those calls are passed through to B. M may do additional things, such as providing two-way communication between A and B. B may be required to change A's data or call its members, but cannot know about A itself. M may resolve this "circular" or "many to many" dependency structure by allowing both A and B to depend on M.