Design Pattern: Adapter Pattern

Summary

Pattern NameAdapter Pattern
Pattern Type Structural Pattern
Other NamesWrapper
ScopeClass or Object (depends on the implementation)
TaglineA bridge between incompatible interfaces
Use casesWhen an interface does not match the new requirement
and it needs to adapt to another interface
(and we want to avoid changing the existing class)
Related Patterns Bridge
Strategy
Decorator
Proxy
Difficulty LevelEasy
Implementations

Definition

When we need to use a class for some specific purpose, but the class does not fulfill the requirement/structure for that. In that case, we can create a class that will work as a bridge between the target and the class we want to use. The class that we are creating as a bridge is called the adapter, as it enables an existing class to adapt to a new use case.

Adapter Diagram
Adapter Diagram

We are not making any changes in the existing class to comply with the Open-Close Principle of the SOLID Principle. Instead of changing the existing class, we are creating a new adapter class.

NOTES

The specific interface that the client already uses is considered the Target.
The wrapper class that we are creating to adapt to the new interface is called the Adapter. This class is responsible for combining functionalities of 2 incompatible and independent interfaces.
The existing class, which is using the wrapper class, is called the Adaptee. This class needs to adapt to the new interface.

The following diagram depicts the relationship between an adapter, adaptee, and the target class.

So, when a function call (request) is made to the Adapter, it mostly forwards the call to Adaptee. Adapter design pattern also combines all the functionality of 2 separate interfaces.

Here is what is expected from an Adapter pattern implementation:

  • Client calls the Adapter following the same interface that the existing target class has.
  • Adapter translates the call, and in turn calls the Adaptee class. 
  • Adaptee class performs the operation and returns the result to the Adapter.
  • Adapter returns the result obtained from the Adaptee. Adapter may perform some additional operations to ensure compatibility with the result.

Use cases

As we don’t want to change the existing class, so we need to create a wrapper class to adapt to the new interface. Use an adapter in the following cases:

  • When an existing class provides the required functionality, but its interface does not match the target class requirement.
  • When two classes or interfaces can not work together, but you need those to work together in a specific way.

Types

The adapter pattern has 2 ways to implement the solution:

  1. Object Adapter: Adapts to an interface using composition.
  2. Class Adapter: Use multiple inheritances.

Implementation of these 2 types of adapters is a little different, Let’s discuss these in detail.

Object Adapter

Object adapter implementation requires single inheritance, and is easy to implement. Here is the detail of the Object adapter:

Existing Condition:

There is an interface IA and few classes implement the interface

interface IA

    function a1()

    function a2()

end interface

class CA1 implements IA

    function a1()
        //. some functionality here
    end function

    function a2()
        //. some functionality here
    end function

end class

class CA2 implements IA

    function a1()
        //. some functionality here
    end function

    function a2()
        //. some functionality here
    end function

end class

New Changes:

As a part of another requirement, there is another interface named IB, and a few classes implement that class.

interface IB

    function b1()

    function b2()

    function b3()

end interface

class CB1 implementes IB

    function b1()
        //. some functionality here
    end function

    function b2()
        //. some functionality here
    end function

    function b3()
        //. some functionality here
    end function

end class

class CB2 implements IB

    function b1()
        //. some functionality here
    end function

    function b2()
        //. some functionality here
    end function

    function b3()
        //. some functionality here
    end function

end class

As interface IA is related to IB, so we want to use all the classes that implement IA, to use as the implementation of IB. This way all the classes implementing interfaces IB and IA can be used as the same interface.

How to implement it?

  1. Create a new class named AdapterA (which is the adapter class) that implements IB.
  2. Define a constructor that accepts an object of type IA.
  3. Add all the functions that are required for implementing interface IB.
  4. Use the function from interface IA inside the implementations of AdapterA, so that the use cases of IB can be fulfilled.

If some operations are not supported in interface IA, and can not be implemented in any direct or indirect way, then throw an Exception.

class AdapterA implements IB

    // define a variable to hold the reference to object of type A
    var IA aObj

    // define constructor which accepts
    function AdapterA(IA ob)
        aObj = ob
    end function

    function b1()
       set returnVal = aObj.a1()
        // perform additional required operations
    end function

    function b2()
        set returnVal = aObj.a2()
        // perform additional required operations
    end function

    function b3()
        // throw exception if this operation is not supported in interface A
        // and there is no direct or indirect way to achive this

        throw Exception
    end function

end class

How to use the Adapter?

Here is the demo of an object adapter.

set objCA1 = new CA1()

set objAdapterA1 = new AdapterA(objCA1)

objAdapterA1.b1()    // which in-tern will use function form class CA1
objAdapterA1.b2()    // which in-tern will use function form class CA1

// or you can do it like below, which is more common style of writting code
set objAdapterA2 = new AdapterA(new CA2())

objAdapterA2.b1()    // which in-tern will use function form class CA2
objAdapterA2.b2()    // which in-tern will use function form class CA2

Class Adapter

Class adapters use multiple inheritances, consider the following condition.

Existing Condition:

There is a class named CA

class CA

    function a1()
        //. some functionality here
    end function

    function a2()
        //. some functionality here
    end function

end class

New Changes:

As a part of another requirement, there is another interface named IB and a few class implementers in that class.

interface IB

    function b1()

    function b2()

    function b3()

end interface

class CB1 implementes IB

    function b1()
        //. some functionality here
    end function

    function b2()
        //. some functionality here
    end function

    function b3()
        //. some functionality here
    end function

end class

class CB2 implements IB

    function b1()
        //. some functionality here
    end function

    function b2()
        //. some functionality here
    end function

    function b3()
        //. some functionality here
    end function

end class

As class CA is related to interface IB, so we want to use class CA, as a part of IB. So class CA implements interfaces IB.

As we don’t want to change the class CA, so we need to introduce an adapter to adapt CA to interface IB.

How to implement it?

  1. Create a new class named AdapterCA (which is the adapter class) which extends class CA and implements IB.
  2. Add all the functions that are required for implementing interface IB.
  3. Use the function from class CA inside the implementations of AdapterCA, so that the use cases of IB can be fulfilled.

If some operation is not supported in class CA, and can not be implemented in any direct or indirect way, then throw an Exception.

class AdapterCA extends CA implements B

    function b1()
       set returnVal = a1() // use function a1() from class CA
        // perform additional required operations
    end function

    function b2()
        set returnVal = a2() // use function a2() from class CA
        // perform additional required operations
    end function

    function b3()
        // throw exception if this operation is not supported in class CA
        // and there is no direct or indirect way to achive this

        throw Exception()
    end function

end class

How to use the Adapter?

Here is how to use the class adapter.

set objAdapterA2 = new AdapterCA()

objAdapterA2.b1()    // which in-tern will use function form class CA
objAdapterA2.b2()    // which in-tern will use function form class CA

Code Implementations

Use the following links to check the implementation of adapter patterns in specific programming languages.

Leave a Comment


The reCAPTCHA verification period has expired. Please reload the page.