How do the Proxy, Decorator, Adapter, and Bridge Patterns differ?
Solution 1:
Proxy, Decorator, Adapter, and Bridge are all variations on "wrapping" a class. But their uses are different.
Proxy could be used when you want to lazy-instantiate an object, or hide the fact that you're calling a remote service, or control access to the object.
Decorator is also called "Smart Proxy." This is used when you want to add functionality to an object, but not by extending that object's type. This allows you to do so at runtime.
Adapter is used when you have an abstract interface, and you want to map that interface to another object which has similar functional role, but a different interface.
Bridge is very similar to Adapter, but we call it Bridge when you define both the abstract interface and the underlying implementation. I.e. you're not adapting to some legacy or third-party code, you're the designer of all the code but you need to be able to swap out different implementations.
Facade is a higher-level (read: simpler) interface to a subsystem of one or more classes. Suppose you have a complex concept that requires multiple objects to represent. Making changes to that set of objects is confusing, because you don't always know which object has the method you need to call. That's the time to write a Facade that provides high-level methods for all the complex operations you can do to the collection of objects. Example: a Domain Model for a school section, with methods like
countStudents()
,reportAttendance()
,assignSubstituteTeacher()
, and so on.
Solution 2:
As Bill's answer says, their use cases are different.
So are their structures.
Proxy and Decorator both have the same interface as their wrapped types, but the proxy creates an instance under the hood, whereas the decorator takes an instance in the constructor.
Adapter and Facade both have a different interface than what they wrap. But the adapter derives from an existing interface, whereas the facade creates a new interface.
Bridge and Adapter both point at an existing type. But the bridge will point at an abstract type, and the adapter might point to a concrete type. The bridge will allow you to pair the implementation at runtime, whereas the adapter usually won't.
Solution 3:
My take on the subject.
All four patterns have a lot in common, all four are sometimes informally called wrappers, or wrapper patterns. All use composition, wrapping subject and delegating the execution to the subject at some point, do mapping one method call to another one. They spare client the necessity of having to construct a different object and copy over all relevant data. If used wisely, they save memory and processor.
By promoting loose coupling they make once stable code less exposed to inevitable changes and better readable for fellow developers.
Adapter
Adapter adapts subject (adaptee) to a different interface. This way we can add object be placed to a collection of nominally different types.
Adapter expose only relevant methods to client, can restrict all others, revealing usage intents for particular contexts, like adapting external library, make it appear less general and more focused on our application needs. Adapters increase readability and self description of our code.
Adapters shields one team from volatile code from other teams; a life savior tool when dealing with offshore teams ;-)
Less mentioned purpose it to prevent the subject class from excess of annotations. With so many frameworks based on annotations this becomes more important usage then ever.
Adapter helps to get around Java limitation of only single inheritance. It can combine several adaptees under one envelope giving impression of multiple inheritance.
Code wise, Adapter is “thin”. It should not add much code to the adaptee class, besides simply calling the adaptee method and occasional data conversions necessary to make such calls.
There are not many good adapter examples in JDK or basic libraries. Application developers create Adapters, to adapt libraries to application specific interfaces.
Decorator
Decorator not only delegate, not only maps one method to another, they do more, they modify behaviour of some subject methods, it can decide not call subject method at all, delegate to a different object, a helper object.
Decorators typically add (transparently) functionality to wrapped object like logging, encryption, formatting, or compression to subject. This New functionality may bring a lot of new code. Hence, decorators are usually much “fatter” then Adapters.
Decorator must be a sub-class of subject's interface. They can be used transparently instead of its subjects. See BufferedOutputStream, it is still OutputStream and can be used as such. That is a major technical difference from Adapters.
Text book examples of whole decorators family is readily in JDK - the Java IO. All classes like BufferedOutputStream, FilterOutputStream and ObjectOutputStream are decorators of OutputStream. They can be onion layered, where one one decorator is decorated again, adding more functionality.
Proxy
Proxy is not a typical wrapper. The wrapped object, the proxy subject, may not yet exist at the time of proxy creation. Proxy often creates it internally. It may be a heavy object created on demand, or it is remote object in different JVM or different network node and even a non-Java object, a component in native code. It does not have to necessary wrap or delegate to another object at all.
Most typical examples are remote proxies, heavy object initializers and access proxies.
Remote Proxy – subject is on remote server, different JVM or even non Java system. Proxy translates method calls to RMI/REST/SOAP calls or whatever is needed, shielding client from exposure to underlying technology.
Lazy Load Proxy – fully initialize object only the first usage or first intensive usage.
Access Proxy – control access to subject.
Facade
Facade is closely associated with design Principle of Least Knowledge (Law of Demeter). Facade is very similar to Adapter. They both wrap, they both map one object to another, but they differ in the intent. Facade flattens complex structure of a subject, complex object graph, simplifying access to a complex structure.
Facade wraps a complex structure, providing a flat interface to it. This prevents client object from being exposed to inner relations in subject structure hence promoting loose coupling.
Bridge
More complex variant of Adapter pattern where not only implementation varies but also abstraction. It adds one more indirection to the delegation. The extra delegation is the bridge. It decouples Adapter even from adapting interface. It increases complexity more than any other of the other wrapping patterns, so apply with care.
Differences in constructors
Pattern differences are also obvious when looking at their constructors.
Proxy is not wrapping an existing object. There is no subject in constructor.
Decorator and Adapter does wrap already existing object, and such is typically
provided in the constructor.Facade constructor takes root element of a whole object graph, otherwise it looks same as Adapter.
Real life example – JAXB Marshalling Adapter. Purpose of this adapter is mapping of a simple flat class to more complex structure required externally and to prevent "polluting" subject class with excessive annotations.