The Adapter design pattern is a structural pattern that allows incompatible interfaces to work together. By doing so, we allow objects from different interfaces to exchange data.
In this article, we are going to learn how to implement the Adapter pattern into our project and when should we use it.
For the main page of this series check out C# Design Patterns.
VIDEO: Adapter Design Pattern in C#.
Initial Project
Let’s imagine that we have functionality in which we convert the list of car manufacturers into JSON format and write it to the screen. But instead of a list, we have been provided with an API that provides us with all the manufacturers in the XML format.
Let’s say we can’t modify the existing API functionality (because of the technical restrictions such as being imported into our project from another solution that we mustn’t modify or as a NuGet package) so we have to find a way around it.
And the proper way to do it is to implement the Adapter pattern to solve this problem.
Let’s start with the creation of the Manufacturer
model and a simple object to XML converter example:
public class Manufacturer { public string Name { get; set; } public string City { get; set; } public int Year { get; set; } }
public static class ManufacturerDataProvider { public List<Manufacturer> GetData() => new List<Manufacturer> { new Manufacturer { City = "Italy", Name = "Alfa Romeo", Year = 2016 }, new Manufacturer { City = "UK", Name = "Aston Martin", Year = 2018 }, new Manufacturer { City = "USA", Name = "Dodge", Year = 2017 }, new Manufacturer { City = "Japan", Name = "Subaru", Year = 2016 }, new Manufacturer { City = "Germany", Name = "BMW", Year = 2015 } }; }
public class XmlConverter { public XDocument GetXML() { var xDocument = new XDocument(); var xElement = new XElement("Manufacturers"); var xAttributes = ManufacturerDataProvider.GetData() .Select(m => new XElement("Manufacturer", new XAttribute("City", m.City), new XAttribute("Name", m.Name), new XAttribute("Year", m.Year))); xElement.Add(xAttributes); xDocument.Add(xElement); Console.WriteLine(xDocument); return xDocument; } }
As we can see, this is a pretty straightforward code. We are collecting manufacturer data, creating a root Manufacturers element and all the Manufacturer sub-elements with its attributes.
After that, we are printing results to the console window to show how the final XML looks like.
This is how the xDocument
should look like:
Now let’s implement a JsonConverter
class:
public class JsonConverter { private IEnumerable<Manufacturer> _manufacturers; public JsonConverter(IEnumerable<Manufacturer> manufacturers) { _manufacturers = manufacturers; } public void ConvertToJson() { var jsonManufacturers = JsonConvert.SerializeObject(_manufacturers, Formatting.Indented); Console.WriteLine("\nPrinting JSON list\n"); Console.WriteLine(jsonManufacturers); } }
This code is even simpler because we only serialize our manufacturer list into a JSON format.
Of course, for the serialization to work we need to install the Newtonsoft.Json
library, so don’t forget to do that.
Excellent, we have our JSON functionality and the provided XML interface. But now, we need to solve a real problem. How to combine those two interfaces to accomplish our task, which is converting manufacturers from XML to JSON format.
Adapter Implementation
As we can see, there is no way to pass an xDocument
to the JsonConverter
class and there shouldn’t be one, so we need to create the adapter class which will make these two interfaces work together.
To do this, we are going to start with the IXmlToJson
interface to define the behavior of our adapter class:
public interface IXmlToJson { void ConvertXmlToJson(); }
Then, let’s continue with the XmlToJsonAdapter
class which is going to implement the IXmlToJson
interface:
public class XmlToJsonAdapter : IXmlToJson { private readonly XmlConverter _xmlConverter; public XmlToJsonAdapter(XmlConverter xmlConverter) { _xmlConverter = xmlConverter; } public void ConvertXmlToJson() { var manufacturers = _xmlConverter.GetXML() .Element("Manufacturers") .Elements("Manufacturer") .Select(m => new Manufacturer { City = m.Attribute("City").Value, Name = m.Attribute("Name").Value, Year = Convert.ToInt32(m.Attribute("Year").Value) }); new JsonConverter(manufacturers) .ConvertToJson(); } }
Excellent. We have created our adapter class which converts the Xml document object into the list of manufacturers and provides that list to the JsonConverter
class.
So, as you can see, we have enabled collaboration between two completely different interfaces by just introducing an adapter class to our project.
Now, we can make a call to this adapter class from our client class:
class Program { static void Main(string[] args) { var xmlConverter = new XmlConverter(); var adapter = new XmlToJsonAdapter(xmlConverter); adapter.ConvertXmlToJson(); } }
Once we start our application, we are going to see the following result:
Great job. We have finished our implementation.
When to Use Adapter
We should use the Adapter class whenever we want to work with the existing class but its interface is not compatible with the rest of our code. Basically, the Adapter pattern is a middle-layer which serves as a translator between the code implemented in our project and some third party class or any other class with a different interface.
Furthermore, we should use the Adapter when we want to reuse existing classes from our project but they lack a common functionality. By using the Adapter pattern in this case, we don’t need to extend each class separately and create a redundant code.
Conclusion
The Adapter pattern is pretty common in the C# world and it is quite used when we have to adapt some existing classes to a new interface. It can increase a code complexity by adding additional classes (adapters) but it is worth an effort for sure.
Thank you for all the examples, but I don’t believe this is the good example of the adapter pattern. Adapter itself should know nothing about JsonConverter. It should convert from XML to IEnumerable<Manufacturer> so that JsonConverter can then consume it. Also, it is a common practice that the adapter implements the target interface (IEnumerable<Manufacturer>) in our case.
We can add an additional IJsonConverter interface and provide a bit different way to supply the manufacturers list to the JsonConverter class and then pass it via DI and not instantiate it inside the adapter class, but this is just a different variation of the same behavior inside the adapter class. I agree it would be better for sure, but I still think that this article shows exactly how the adapter class should behave and what is its purpose. Now, the way you want to implement it is completely up to you.
My point is that the adapter should rather be XmlToListAdapter as JsonConverter seems to be the consumer. Adapters implement interfaces that are required by consumers. Adapter in your example implements IXmlToJson, but that interface is not consumed anywhere.
I understand your point but just because we used the result from an adapter class to print the result it doesn’t mean that it can’t be used in a class that needs XML data converted to JSON data. We just printed the results for the example’s sake and to avoid additional complexity. If we want to be perfectly accurate with the architecture neither GetXML nor ConvertToJSON should print anything, they should return values inside the adapter class so it could get them back to the consumer, but that would add just an additional complexity to this article, which I tried to avoid.
I thought you tried to avoid the complexity in the article and the usage of IXmlToJson is implied, but also thought that the consumer is the important part of the adapter pattern. Otherwise, the code in ConvertXmlToJson can be just inlined in Main() and it won’t make a difference. I find your site very helpful by the way with lot of useful content. Thank you for sharing all that
Hi,
Thanks for this article . I have one dought that why we are using adapter here. On the top we are doing XML to json format in class . We can use that. Please provide answer to me .
Thanks ,
Ajay
Hello Ajay. We have a class that provides us with the XML format data and the class which transforms a List to the JSON format data. Between those two we have to create a bridge (adapter) class to transform XML to a List and than we can send that list to the JSON convert class. The ConvertToJson is our custom method inside the XMLToJsonAdapter class.
Hi. Adapter pattern is structural pattern not creational. Thanks for the examples.
Hello Edwar, thank you for that suggestion. My mistake. All the best.
I’m intrigued, why is this a better solution than creating a subclass of the XmlConverter class and implement the method that provides json in that?
Hello ede. Thank you for reading this article and for commenting as well. To answer your question, think of the XmlConverter as a provided API and not something that we have coded in our project. Having that in mind, the XmlConverter class could be sealed as much as we know, and then you will have no possibility to inherit from it. The second thing is that there is a multiple reasons why composition is better then inheritance (you can read about that in great detail in variety of articles on the internet) thus many different design patterns use composition over inheritance as well. Finally, we are not saying that this is ONLY and THE BEST way, no way 😀 You can implement Adapter pattern in different ways but this is just one of them.