Luna Tech

Tutorials For Dummies.

Adapter Pattern (Wrapper)


0. What is the Adapter Pattern?

What is the problem it’s solving?

Incompatible interfaces between a client and a service-provider.

How to solve the problem?

Adapter convert the interface of one class into an interface a client expects.

Sometimes adapters are referred to as wrappers, because they wrap an incompatible class into a compatible one.

1. What software design principles apply to this pattern?

当出现以下情况的时候,可以考虑用 Adapter 解决问题。

  1. Polymorphism(多态)can be used to avoid complex conditional logic
  2. Prefer loose coupling to third party dependencies (e.g., files, APIs should be easily integrated)
  3. Improve testability of the clients

2. How to apply this pattern?

Follow SOLID principles:

Different Kinds of Adapters

  1. Object Adapters
  2. Class Adapters

The difference is how they reference the class that they are wrapping or adapting.

Adapter can work with service providers as well as wrapping result types.

Object Adapter

  1. Hold an instance of the Adaptee class
  2. Can implement an Adapter interface or inherit from the Adapter type
  3. Use composition and single inheritance

If an Adapter implementation uses composition instead of inheritance, it is an Object Adapter.

Class Adapter

  1. Inherits from the Adaptees and the Adapter type
  2. Requires multiple inheritance

One variation of class adapter that doesn’t require multiple class inheritance simply implements the Adapter Interface, this variation can be used in languages like C# and Java (they don’t support multiple inheritance).

C# Adapter

In C#, the Adapter pattern uses composition and is known as an object adapter. The Adapter implementations will contain instances of the incompatible type and will delegate calls to this instance’s incompatible methods or properties.

3. Example

Usually you’ll use the Adapter pattern when you are already going to work with a particular interface to an existing class implementation.

  1. Take the if-else statements and break them out into two different class implementations (extract the logic out)
  2. When the extracted methods belong to different classes and have different signatures (basically different interfaces are present)
  3. Identify an Interface that we can use commonly across these classes (least input required to execute the method)
  4. Create the Interface with suitable signature (e.g., async functions should have return type of Task)
  5. Refactor the code by creating different implementations of the Adapter Interface (this is the core of the adapter pattern)

4. What are the similar or frequently used patterns with Adapter?

Similar but different design intent patterns:

Patterns that commonly used together: