Summary
Pattern Name | Adapter Pattern |
Pattern Type | Structural Pattern |
Other Names | Wrapper |
Scope | Class or Object (depends on the implementation) |
Tagline | A bridge between incompatible interfaces |
Use cases | When 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 Level | Easy |
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.
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 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:
- Object Adapter: Adapts to an interface using composition.
- 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?
- Create a new class named AdapterA (which is the adapter class) that implements IB.
- Define a constructor that accepts an object of type IA.
- Add all the functions that are required for implementing interface IB.
- 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?
- Create a new class named AdapterCA (which is the adapter class) which extends class CA and implements IB.
- Add all the functions that are required for implementing interface IB.
- 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.