Adapter Design Pattern

A Software Design Pattern that allows the interface of an existing class to be used from another interface. It is often used to make existing classes work with others without modifying their source code.

It helps two incompatible interfaces to work together.

Real Work Example

Adapter Design Pattern Real Work Example
Figure 1: A real world example of Adapter Design Pattern. By using an adapter you can use the rounded corner socket.

Software Engineering Examples
  • ADO.Net SqlAdapter
  • MySqlAdapter
  • OracleAdapter
When to Use:
  • We want to allow two classes to work together.
  • When we don't want to break clients that are using the adaptee class. This very important in api that has several versions;
  • We want preserve Open/Close Principle;
  • When we are using third party api and we can't edit the codes;
  • When we want to extend the functionality of existing class.
UML Class Diagram


Participants
Class/Interface Description
ITarget An interface defines the properties and methods to be implemented by the Adapter.
Adapter A concrete class that ITarget interface. It handles communication between the client and the adaptee.
Adaptee This contains the functionality but it can be use by client because it's incompatible. The existing class.
Client It uses/consumes the adaptee through the adapter.

Sample Implementation

This is a sample application that uses Adapter Design Pattern to allow a legacy code to be use by client that uses strongly type variables. We can call this Book Order application.

The legacy code reads and parse xml files (books ordered) and stores it arraylist then finally gives to a client that uses it. We want the result to be strongly type because arrays are difficult to handle. Adaper Design Pattern solves this problem.

Download Source Code


The Project Structure

The BookOrder.xml is stored in bin/debug folder.

UML Class Diagram

Mapping
Adapter Design Pattern Book Order
ITarget IGetBookOrder
Adapter BookOrder
Adaptee GetXMLBookOrder
Client Program

The Order class is use for storing data.

The Codes

The POCO
Order.cs
namespace AdapterDesignPattern.POCO
{
public class Order
{
public int Id{get; set;}
public string Title {get; set;}
public string ISBN {get; set;}
public string Author {get; set;}
public double Price {get; set;}
public int Quantity {get; set;}
public string Customer {get; set;}
}
}

The Adapter

IGetBookOrder.cs
using AdapterDesignPattern.POCO;
using System.Collections.Generic;
namespace AdapterDesignPattern.Interface
{
public interface IGetBookOrder
{
List<Order> GetBookOrders();
}
}
BookOrder.cs
using AdapterDesignPattern.Adaptee_LegacyCode;
using AdapterDesignPattern.Interface;
using AdapterDesignPattern.POCO;
using System;
using System.Collections;
using System.Collections.Generic;
namespace AdapterDesignPattern.Adapter_NewCode
{
public class BookOrder : GetXMLBookOrder, IGetBookOrder
{
ArrayList BookOrderArray;
List<Order> BookOrders = new List<Order>();
List<Order> IGetBookOrder.GetBookOrders()
{
BookOrderArray = ReadXML();
foreach (string[] Order in BookOrderArray)
{
BookOrders.Add(new Order { Title = Order[0], ISBN = Order[1], Author = Order[2], Price = Convert.ToDouble(Order[3]), Quantity = Convert.ToInt32(Order[4]), Customer = Order[5] });
}
return BookOrders;
}
}
}
The Adaptee

GetXMLBookOrder.cs
using System.Collections;
using System.IO;
using System.Xml;
using System.Xml.Linq;
namespace AdapterDesignPattern.Adaptee_LegacyCode
{
public class GetXMLBookOrder
{
public ArrayList ReadXML()
{
ArrayList Orders = new ArrayList();
string[] Order;
string xmlString = XDocument.Load(@"XMLData\BookOrder.xml").ToString();
// Read the XML
Order = new string[6];
using (XmlReader reader = XmlReader.Create(new StringReader(xmlString)))
{
while (reader.Read())
{
switch (reader.Name)
{
case "Title" :
if (reader.Read()) {
Order[0] = reader.Value.Trim();
reader.Read();
}
break;
case "ISBN":
if (reader.Read())
{
Order[1] = reader.Value.Trim();
reader.Read();
}
break;
case "Author":
if (reader.Read())
{
Order[2] = reader.Value.Trim();
reader.Read();
}
break;
case "Price":
if (reader.Read())
{
Order[3] = reader.Value.Trim();
reader.Read();
}
break;
case "Quantity":
if (reader.Read())
{
Order[4] = reader.Value.Trim();
reader.Read();
}
break;
case "Customer":
if (reader.Read())
{
Order[5] = reader.Value.Trim();
Orders.Add(Order);
Order = new string[6];
reader.Read();
}
break;
}
}
}
return Orders;
}
}
}
The Client

Program.cs
using System;
using System.Collections.Generic;
using AdapterDesignPattern.Interface;
using AdapterDesignPattern.Adapter_NewCode;
using AdapterDesignPattern.POCO;
namespace AdapterDesignPattern
{
class Program
{
static void Main(string[] args)
{
IGetBookOrder GetBookOrder = new BookOrder();
List<Order> _BookOrder = GetBookOrder.GetBookOrders();
foreach (Order _Order in _BookOrder)
{
Console.WriteLine(String.Format("Title :{0}", _Order.Title));
Console.WriteLine(String.Format("ISBN :{0}", _Order.ISBN));
Console.WriteLine(String.Format("Author :{0}", _Order.Author));
Console.WriteLine(String.Format("Price :{0}", _Order.Price));
Console.WriteLine(String.Format("Quantity :{0}", _Order.Quantity));
Console.WriteLine(String.Format("Customer :{0}", _Order.Customer));
Console.WriteLine("");
}
}
}
}

The Output

Hope this is helpful. Thanks for viewing. Your thoughts!