Before diving into the details of Adapter pattern, we will analyze what is Structural pattern.
Structural Pattern
In software engineering, structural design patterns are design patterns that ease the design by identifying a simple way to realize relationships between entities. Structural patterns are concerned with how classes and objects are composed to form larger structures. Structural class patterns use inheritance to compose interfaces or implementations. As a simple example, consider how multiple inheritance mixes two or more classes into one. The result is a class that combines the properties of its parent classes. This pattern is particularly useful for making independently developed class libraries work together.
Adapter pattern is a type of Structural pattern.
Adapter Pattern
Sometimes, a toolkit class that’s designed for reuse isn’t reusable only because its interface doesn’t match the domain-specific interface an application requires. Thus Adapter pattern acts as a bridge between two incompatible interfaces. This pattern involves a single class called adapter which is responsible for communication between two independent or incompatible interfaces.
For example: If I have a source providing me something in some format and my target is expecting that stuff in some other format, then I can hook in a module in between these two guys that will do the conversion. This entity working in between these two is my adapter.
The classic example is, when we go to European countries, we need a Adapter which will act as a bridge between our Standard AC Plug and European Wall outlet due to difference in the plug point. In programming too, this is valid as many times we have a old system which has implemented some interface and the new system which we have developed doesn't honor this, thus creating problems for us. During these kind of scenarios, we can effectively use Adapter pattern.
Below is the image:
There are few keywords when we are talking about Adapter Pattern.
ITarget
: This is an interface which is used by the client to achieve its functionality/request. Adapter
: This is a class which implements the ITarget
interface and inherits the Adaptee
class. It is responsible for communication between Client
and Adaptee
. Adaptee
: This is a class which has the functionality required by the client. However, its interface is not compatible with the client. Client
: This is a class which interacts with a type that implements the ITarget
interface. However, the communication class called adaptee
is not compatible with the client.
Now let us assume the above image and keywords and design our own example:
Let us look now at our Client
also know as TwoPinPlug
.
class TwoPinPlug
{
private ITarget target;
public TwoPinPlug(ITarget _target)
{
target = _target;
}
public void MakeRequestToConvert()
{
Console.WriteLine("Requesting to convert from Standard AC 2 pin plug to European Wall outlet");
target.Convert();
}
}
Let us look now at our ITarget
:
interface ITarget
{
void Convert();
}
Let us now look at our Adapter
:
class Adapter : ThreePinPlugPoint,ITarget
{
public void Convert()
{
Console.WriteLine("Converting from Standard AC 2 pin plug to European Wall outlet");
InsertPlug();
}
}
And finally, let us now look at our Adaptee
also know as ThreePinPlugPoint
:
class ThreePinPlugPoint
{
public void InsertPlug()
{
Console.WriteLine("Converted and Standard AC 2 pin plug inserted in European Wall outlet");
Console.ReadLine();
}
}
When we run, we get the below result:
Use the Adapter pattern when:
- you want to use an existing class, and its interface does not match the one you need.
- you want to create a reusable class that cooperates with unrelated or unforeseen classes, that is, classes that don’t necessarily have compatible interfaces.
- (object adapter only) you need to use several existing subclasses, but it’s impractical to adapt their interface by subclassing every one. An object adapter can adapt the interface of its parent class.
Happy coding !!! :)