Adapter
This is the 6th article of the design pattern series and the first article of the structural design pattern so let’s talk a bit about structural design patterns and then we will dive into Adapter design pattern.
What are structural design patterns?
Structural design patterns are concerned with how classes and objects are composed to form larger structures. They focus on simplifying the design by identifying simple ways to realize relationships between entities.
Why do we need structural design patterns?
List of Structural Design Patterns
Here are some common structural design patterns along with brief descriptions for each one:
To remember the list of structural design patterns you need to remember first letter of them is this order (ABCD FF P)
1. Overview of the Adapter Pattern
The Adapter Design Pattern is a structural pattern that allows incompatible interfaces to work together. It acts as a bridge between two incompatible interfaces by providing a wrapper that translates one interface to another. It involves creating an adapter class that implements the target interface and delegates the calls to the adaptee object, which has a different interface. This enables objects with incompatible interfaces to work together seamlessly.
I created a solution in my GitHub that contains a project called Adapter for this article. You can find it here:
2. Structure of the Adapter Pattern
3. Implementation in C#
Let's demonstrate the Adapter pattern with a simple example of adapting a legacy class to work with a modern interface:
// Target Interface
public interface IModernTarget
{
string[] Request();
}
// Adaptee
public class LegacyAdaptee
{
public void SpecificRequest()
{
return "item1,item2,item3";
}
}
// Adapter
public class Adapter : IModernTarget
{
private readonly LegacyAdaptee _legacyAdaptee;
public Adapter(LegacyAdaptee legacyAdaptee)
{
_legacyAdaptee = legacyAdaptee;
}
public string[] Request()
{
// Call the legacy method and adapt the interface
return _legacyAdaptee.SpecificRequest().Split(new char[] {','});
}
}
In this example our modern class needs to return string array in Request but legacy adapter return a comma separated string which doesn't match to what we need so we used an Adapter to solve this problem.
Recommended by LinkedIn
4. Usage of the Adapter Pattern
class Program
{
static void Main(string[] args)
{
// Create the legacy adaptee
var legacyAdaptee = new LegacyAdaptee();
// Create the adapter
var adapter = new Adapter(legacyAdaptee);
// Use the adapter through the modern interface
string[] result = adapter.Request();
}
}
As you may noticed, we passed legacy adaptee to the Adapter and just call its Request method to get what we need.
5. Benefits of the Adapter Pattern
6. When to Use the Adapter Pattern
Existing Adapter in .NET
Here are a few examples of existing adapters in .NET along with explanations of why they can be considered instances of the Adapter pattern:
1. StreamReader and StreamWriter in System.IO namespace
2. ArrayAdapter class in System.Collections namespace
3. HttpRequestWrapper and HttpResponseWrapper classes in ASP.NET
Conclusion
In conclusion, the Adapter Design Pattern provides a straightforward solution for integrating classes with incompatible interfaces. By following the principles outlined in this article and using the provided example, you can leverage the Adapter pattern in your C# applications to achieve seamless integration between disparate components.
#designpattern #structuraldesignpattern #adapter #csharp #dotnet