 .NET 1.1+Adapter Design PatternThe adapter pattern is a design pattern that is used to allow two incompatible types to communicate. Where one class relies upon a specific interface that is not implemented by another class, the adapter acts as a translator between the two types.
What is the Adapter Pattern?
The adapter pattern is a Gang of Four design pattern. This is a structural pattern as it defines a manner for creating relationships between classes. The adapter design pattern is used to provide a link between two otherwise incompatible types by wrapping the "adaptee" with a class that supports the interface required by the client.
Let's take an example where we have a personnel system and an intranet solution that displays, amongst other things, a telephone list. It may be that the personnel system includes methods that permit the retrieval of employees, including their name, job title and telephone number. The intranet solution may include a plug-in system that can be used to source this data but the plug-in must provide a specific interface that is not supported by the personnel software.
In this case, we can create a new class to be an adapter. This class will provide the intranet's desired interface and will hold an object of the type required by the personnel system. When the intranet makes a request, this request can be passed to the correct method of the personnel system. The response from the personnel system will then be translated to a format that can be used by the intranet.
Implementing the Adapter Pattern

The UML class diagram above describes an implementation of the adapter design pattern. The items in the diagram are described below:
- Client. The client class is that which requires the use of an incompatible type. It expects to interact with a type that implements the ITarget interface. However, the class that we wish it to use is the incompatible Adaptee.
- ITarget. This is the expected interface for the client class. Although shown in the diagram as an interface, it may be a class that the adapter inherits. If a class is used, the adapter must override its members.
- Adaptee. This class contains the functionality that is required by the client. However, its interface is not compatible with that which is expected.
- Adapter. This class provides the link between the incompatible Client and Adaptee classes. The adapter implements the ITarget interface and contains a private instance of the Adaptee class. When the client executes MethodA on the ITarget interface, MethodA in the adapter translates this request to a call to MethodB on the internal Adaptee instance.
The following shows the basic code of the adapter design pattern implemented using C#. In this case, the object that implements ITarget is passed to the client's constructor. However, it could quite easily be provided as a parameter of a method.
public class Client
{
private ITarget _target;
public Client(ITarget target)
{
_target = target;
}
public void MakeRequest()
{
_target.MethodA();
}
}
public interface ITarget
{
void MethodA();
}
public class Adaptee
{
public void MethodB()
{
Console.WriteLine("MethodB called");
}
}
public class Adapter : ITarget
{
Adaptee _adaptee = new Adaptee();
public void MethodA()
{
_adaptee.MethodB();
}
}
Example Adapter
To demonstrate further, we will now create an example of the adapter. This example will perform the translation of employee details between the personnel system and the intranet telephone list described earlier in this article. As the implications of such a system could be very large, we will create a very simplified, and rather contrived, example.
Let's start by creating the intranet telephone list class. This class will perform a request for employee details by calling the GetPhoneList method on an object that implements the IIntranetPhoneList interface. This object will be provided during instantiation. The method expects that the phone list will be returned in a comma-separated format containing a name, job title and telephone number. Employee records will be separated by a new line character. For simplicity, this string is outputted to the console by the ShowPhoneList method.
public class Intranet
{
private IIntranetPhoneList _phoneListSource;
public Intranet(IIntranetPhoneList phoneListSource)
{
_phoneListSource = phoneListSource;
}
public void ShowPhoneList()
{
string phoneNumbers = _phoneListSource.GetPhoneList();
Console.WriteLine(phoneNumbers);
}
}
public interface IIntranetPhoneList
{
string GetPhoneList();
}
Next we will examine the Personnel system class. This class returns the required data for the phone list but in a different format. Each employee is represented by an array containing three strings for the telephone number, name and job title. To return multiple employees, an array of arrays is generated.
NB: This awkward return value is included here because it is reasonably simple to convert to the target string. This type of return value is not advisable in a production system.
public class PersonnelSystem
{
public string[][] GetEmployees()
{
string[][] employees = new string[4][];
employees[0] = new string[] { "1201", "Jim", "Team Leader" };
employees[1] = new string[] { "1202", "Bob", "Developer" };
employees[2] = new string[] { "1203", "Sue", "Developer" };
employees[3] = new string[] { "1204", "Dan", "Tester" };
return employees;
}
}
As the two types are incompatible, we can create an adapter to undertake the required translation. The adapter performs two tasks in this case. Firstly a call to GetPhoneList is rerouted to GetEmployees. Secondly, the arrays are converted to the desired comma-separated format before they are returned to the Intranet class.
public class PhoneListAdapter : IIntranetPhoneList
{
private PersonnelSystem _personnel;
public PhoneListAdapter(PersonnelSystem personnel)
{
_personnel = personnel;
}
public string GetPhoneList()
{
string[][] employees = _personnel.GetEmployees();
StringBuilder phoneList = new StringBuilder();
foreach (string[] employee in employees)
{
phoneList.Append(employee[1]);
phoneList.Append(',');
phoneList.Append(employee[2]);
phoneList.Append(',');
phoneList.Append(employee[0]);
phoneList.Append('\n');
}
return phoneList.ToString();
}
}
Testing the Adapter
To test the adapter example we can use the Main method of a console application. As you can see, we first create a PersonnelSystem object. We then create a new adapter that holds a reference to the PersonnelSystem object. Finally, we can instantiate our Intranet object, passing the adapter to use as its source of telephone list information. The call to ShowPhoneList is intercepted by the adapter so that the data can be retrieved from the incompatible PersonnelSystem object and correctly formatted for output.
static void Main(string[] args)
{
PersonnelSystem personnel = new PersonnelSystem();
PhoneListAdapter adapter = new PhoneListAdapter(personnel);
Intranet intranet = new Intranet(adapter);
intranet.ShowPhoneList();
}
/* OUTPUT
Jim,Team Leader,1201
Bob,Developer,1202
Sue,Developer,1203
Dan,Tester,1204
*/
|