(Coursenotes for CSC 305 Individual Software Design and Development)

Proxy and Adapter Design Patterns

Software modules sometimes need to interact with other services that may need some “middle management” for various reasons. For example

The Proxy design pattern

The proxy design pattern is simple in principle.

You have some client code that interfaces with some external service, and for whatever reason (see examples above), you need to mediate or control access to that service. You create a Proxy class that “pretends” to be the external service, and your client only interfaces with that Proxy, though they are not aware that they’re not getting “the real thing”.

So in the DB example above, you would add a Proxy class that:

This is as opposed to the proxy-less solution with each client having to keep track of their own copies of the DB libraries, or the clients having to re-initialise the DB drivers each time.

So the Proxy design pattern involves the following pieces:

You can get a lot done with just the two pieces above. The Proxy pattern becomes useful when you need the extra processing steps before and/or after using the Service. To do that, you add the following:

Pros and cons

The Proxy pattern is helpful in the following ways

Two drawbacks are:

The Adapter design pattern

The Adapter pattern is similar in intent to the Proxy pattern. You have two modules that need to interact with each other, but need some “middle management” in order to do this.

In the Proxy pattern, our possible reasons were because the second module in this “handshake” is a heavyweight Service, or a service that needs some additional pre- and post-processing while it’s being used.

However there is another reason for requiring “middle management” between client and service: they are not interoperable.

As a real-world example, consider the different power plugs used in different countries. Each time I visit home in India, I need adapters in order to plug in my laptop charger (American plugs) into the sockets at home (Indian sockets). Similarly, we’ve used used dongles to connect projects or external monitors to our laptops (variously, with HDMI, USB-C, Thunderbolt, or, god forbid, VGA sockets). This “handshake” between two systems that are not interoperable is enabled by the use of an Adapter that “translates” between the two systems.

So the pattern looks very familiar to the Proxy pattern:

You have

This pattern may be more useful when you can’t change the Service that your Client needs to use, for whatever reason (e.g., competing standards, proprietary software, etc.).

For example, suppose you’re trying to merge or analyse data coming from two sources, but one source emits data in JSON format, and another emits data in XML format. If your client only works with the JSON format, you can create an Adapter that converts XML data to JSON data, and your Client uses that Adapter.

This promotes adherence to the Single Responsibility Principle, because your Client is not being bloated with code to handle data conversion.

As an example “in the wild”, consider the InputStreamReader class in the Java standard library. It is a self-described “bridge from byte streams to character streams: It reads bytes and decodes them into characters using a specified charset”.