Shadman Kudchikar

Adapter Design Pattern In C#

Adapter Design Pattern In C#

Contents

Introduction

The Adapter design pattern is one of the most common, and most useful patterns available to us as software developers. When you have a class that needs to utilize a particular interface, and you have a library that includes the functionality you need, but it doesn’t use the interface that you require. You can achieve the reuse of that library’s code by creating an Adapter class that sits between your client code, and the code that’s in this library, and adapts one interface to the other.

Structure

Adapter Design Pattern Structure Let’s look at the structure of the Adapter Pattern using this UML diagram. The two basic players within this example are the Client, and the Adaptee, shown above.

Now,

The Client needs some of the logic that exists within the Adaptee. Specifically, there is this AdaptedOperation that has the code that the Client wants to be able to utilize. Unfortunately, the Client has been written in such a way that it cannot directly call this AdaptedOperation because its interface is not the one that the Client expects. This is where the Adapter Pattern comes into play.

First,

The Adapter interface is created, exposing an Operation that has the interface the Client expects.

Next,

For each different implementation required, at a minimum, one, its different ConcreteAdapter is created that takes that Operation and implements it, such that that code calls the AdaptedOperation. In this way, the Client will now be able to call the Operation on the ConcreteAdapter, which in turn will call the AdaptedOperation on the Adaptee.

The Client really wants to use the Adaptee directly, but unfortunately it can’t due to the incompatible interface. The Adapter Pattern is simply allowing us to achieve this despite this incompatibility.

Let’s see a simple example,

public interface IPerson
{
    string Name { get; set; }
}

public interface IFrenchPerson
{
    string Nom { get; set; }
}

public class Person : IPerson
{
    public string Name { get; set; }
}

public class FrenchPerson : IFrenchPerson
{
    public string Nom { get; set; }
}

public class PersonService
{
    public void PrintName(IPerson person)
    {
        Debug.Write(person.Name);
    }
}

public class FrenchPersonAdapter : IPerson
{
    private readonly IFrenchPerson frenchPerson;

    public FrenchPersonAdapter(IFrenchPerson frenchPerson)
    {
        this.frenchPerson = frenchPerson;
    }

    public string Name
    {
        get { return frenchPerson.Nom; }
        set { frenchPerson.Nom = value; }
    }
}
var service = new PersonService();
var person = new Person();
var frenchPerson = new FrenchPerson();

service.PrintName(person);
service.PrintName(new FrenchPersonAdapter(frenchPerson));

As you can see from the above code FrenchPerson is now behaving like a Person Class with the use of FrechPersonAdapter and thus is now compatible with PersonService.

In the above example PersonService class becomes Client, IPerson interface becomes our AdapterInterface and FrenchPerson class becomes Adaptee, as FrenchPerson is incompatible with PersonService we create FrenchPersonAdapter by implementing IPerson AdapterInterface.

Real World Example

If you yourself are writing a library, or a framework, and you want to ensure that it’s useable by future classes that may not even have been written yet, and so you cannot be certain what their interface will be, you can add support for an Adapter as part of your interface for your code, and this will make it easier for other future applications to use your code.

This idea is used within the. NET Framework Library itself, you will find if you look at ADO. NET in the System.Data namespace using a tool such as Reflector, that there is a class called the IDataAdapter, and that IDataAdapter has a number of derived types, including a concrete class called DataAdapter, also you’ll find the DbDataAdapter, Odbc, OleDb, and SqlDataAdapters. Each of these implements at its core the IDataAdapter interface.

Where To Apply?

You should consider using the Adapter Pattern whenever you want to use an existing class’s functionality, but its interface is not the one that you require.

Another scenario, if you’re trying to create reusable code, and you don’t want to tie it too tightly to a particular implementation, you should use some kind of an Adapter interface as what you’re code depends on, so that future clients could implement their own version of that Adapter and still make use of your code.

You’ll also find the Adapter Pattern useful if there are several existing implementations of code that you want to be able to use, and it’s impractical to adapt each of their interfaces by sub-classing everyone. By implementing the Adapter Pattern, and just writing an Adapter for each of these subclasses, for instance, maybe you have a Data Access class, one for SQL Server, another for Oracle, another for DB2, you would be able to create a Data Adapter, and then create just the Adapter classes for each of those different implementations rather than trying to change those implementations directly to expose the interface that you require.

Summary

The Adapter Pattern is used to wrap a needed class with one that implements a required interface.

Also,

If you write your Client classes so that they depend on Adapters, it allows you to future-proof these classes so they can be made to work with future versions of code that does not use interfaces that you foresaw when you wrote your Client Library.

You should remember the Open/Closed Principle, which states that modules should be open to extension, but closed to modification, and by utilizing the Adapter Pattern in your implementations of your code, you allow for your code to better follow the Open/Closed Principle.

References


comments powered by Disqus