How do the Proxy, Decorator, Adapter, and Bridge Patterns differ?

82,424

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.

Solution 4

There's a great deal of overlap in many of the GoF patterns. They're all built on the power of polymorphism and sometimes only really differ in intent. (strategy vs. state)

My understanding of patterns increased 100 fold after reading Head First Design Patterns.

I highly recommend it!

Solution 5

All good answers from experts have already explained what does each pattern stands for.

I will decorate key points.

Decorator:

  1. Add behaviour to object at run time. Inheritance is the key to achieve this functionality, which is both advantage and disadvantage of this pattern.
  2. It modifies the behaviour of interface.

e.g. (with chaining ) : java.io package classes related to InputStream & OutputStream interfaces

FileOutputStream fos1 = new FileOutputStream("data1.txt");  
ObjectOutputStream out1 = new ObjectOutputStream(fos1);

Proxy:

  1. Use it for lazy initialization, performance improvement by caching the object and controlling access to the client/caller. It may provide alternative behaviour or call real object. During this process, it may create new Object.
  2. Unlike Decorator, which allows chaining of objects, Proxy does not allow chaining.

e.g.: java.rmi package classes.

Adapter:

  1. It allows two unrelated interfaces to work together through the different objects, possibly playing same role.
  2. It modifies original interface.

e.g. java.io.InputStreamReader (InputStream returns a Reader)

Bridge:

  1. It allows both abstractions and implementations to vary independently.
  2. It uses composition over inheritance.

e.g. Collection classes in java.util. List implemented by ArrayList.

Key notes:

  1. Adapter provides a different interface to its subject. Proxy provides the same interface. Decorator provides an enhanced interface.
  2. Adapter changes an object's interface, Decorator enhances an object's responsibilities.
  3. Decorator and Proxy have different purposes but similar structures
  4. Adapter makes things work after they're designed; Bridge makes them work before they are.
  5. Bridge is designed up-front to let the abstraction and the implementation vary independently. Adapter is retrofitted to make unrelated classes work together
  6. Decorator is designed to let you add responsibilities to objects without subclassing.

Have a look at great SE questions/articles regarding examples of various design patterns

When to Use the Decorator Pattern?

When do you use the Bridge Pattern? How is it different from Adapter pattern?

Differences between Proxy and Decorator Pattern

Share:
82,424
Charles Graham
Author by

Charles Graham

Programmer from Philly.

Updated on June 12, 2020

Comments

  • Charles Graham
    Charles Graham about 4 years

    I was looking at the Proxy Pattern, and to me it seems an awful lot like the Decorator, Adapter, and Bridge patterns. Am I misunderstanding something? What's the difference? Why would I use the Proxy pattern versus the others? How have you used them in the past in real world projects?