Understanding and Implementing the Adapter Pattern in C# and C++

This article aims at understanding when we could find the Adapter pattern useful and how can we have a rudimentary implementation of the Adapter pattern using C# and C++.

Background

It was almost 6 years back, at the very beginning of my career, that one of my clients told me to write an adapter. Back then I was unaware of the “Adapter Pattern” but I took his words literally and started my work. I did the required task and wrote an adapter. I think this pattern is something that anyone will find very easy to understand and even implement.

What exactly is an adapter? 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. I remember the adapter that I used to power up my 16 bit gaming console (expecting 9 volts of power) using a 220 volt power supply.

realworld

The Adapter we are going to talk about here is also on the same lines but it works for classes and objects. If I have a class that is exposing some functions but my client is expecting some other interface, then I can have an adapter in between. The benefit of having an adapter is that the client need not be changed every time I choose to change my underlying object that is being used. I just have to have an adapter written for the new target and the client code will work seamlessly.

Using the Code

GoF defines Adapter pattern as “Convert the interface of a class into another interface that the clients expect. Adapter lets classes work together that couldn’t otherwise because of incompatible interfaces.”

adapterGof

Let us try to understand this class diagram:

  • Target: Defines the interface that the client uses.
  • Adapter: It uses (adapts) the Adaptee’s interface and exposes the Target interface to the client.
  • Adaptee: This is the object whose interface needs to be adapted.
  • Client: It uses the Adaptee functionality via the adapter interface, i.e., Target.

One good example of when we could find this pattern useful is when visualizing an MP3 player application. This MP3 player application was developed on top of some library (say DirectX). The application makes DirectX specific calls to achieve the playback functionality. After some time, there is a requirement of using XNA for playback instead of DirectX. This could mean either rewriting the complete application to change the DirectX specific calls to XNA specific calls, or we could simply write an adapter for XNA in such a way that the client application could work with minimum or no changes.

Let us try to write a small toy application to demonstrate this concept. We will create a small client that will use two libraries (dummy) to perform some operations. These two libraries expose different interfaces so we will write a small adapter to use the libraries. Let us look at the two libraries first, Adaptee:

Now let us look at the C++ Implementation of these Libraries i.e. Adaptee

Now let us write the adapter interface for our concrete adapters, i.e., Target from the above class diagram.

The C++ Implementation of the Target i.e. IAdapter

and now we will write the concrete Adapter classes to use the two libraries:

The C++ Implementation of Concrete Adapters is

So now we have a single interface that the client can use. The respective adapters will take care of making the calls to the respective underlying objects. Let us see how the Client can use this adapter.

and finally the C++ Implementation of Client

So now the client can use the same interface to perform operations using both underlying objects. The Adapter pattern is particularly useful when we have two classes that perform similar functions but have different interfaces. The client wants to use both classes, so instead of having conditional code scattered all around the client code, it would be better and simpler to understand if these two classes share the same interface. We cannot change the class interfaces, but we can have an Adapter which allows the client to use a common interface to access the underlying classes.

Before wrapping up, let us look at the class diagram of our small application and compare it with the GoF diagram.

mapping

Points of Interest

This article was written from a beginner’s point of view and demonstrated the implementation of the Adapter pattern using a non-realistic example. The Adapter pattern is a really simple but important Design Pattern. The .NET Framework uses this pattern in its core to use the legacy COM component.

Download sample code for this article: AdapterTestC#,  AdapterTestCPP