Leverage the Adapter design pattern to map incompatible interfaces, increase code coverage, and reduce complexities in designs Design patterns are solutions to recurring problems and complexities in software design. Design patterns are categorized as Creational, Structural, or Behavioral. Creational patterns are used to create and manage the mechanism of creating instances of classes. Structural patterns are used to realize the relationships among the entities. Behavioral design patterns deal with object collaboration and delegation of responsibilities. The Adapter pattern is a structural design pattern that acts as a bridge between two interfaces that are incompatible. The term “Adapter” is used to represent an object that enables two mutually incompatible interfaces to communicate and collaborate. In essence, the Adapter pattern enables classes (that have incompatible interfaces) to work together and their objects communicate if need be. There are certain types of adapters that implement he interfaces of both the Target and the Adaptee. Such types of Adapters are known as Two-Way adapters. You also have two distinct types of adapters namely, Class Adapters and Object Adapters. While the former uses inheritance, the latter uses composition to fix incompatibility issues in your designs. You can use the adapter design pattern when you need to use a third-party library that is incompatible with the types you have in your application. The following is the list of the types that participate in a typical implementation of the Adapter pattern: Target Adapter Adaptee Client Let’s understand this with an example. Suppose two people who speak and understand different languages need to communicate — one may be French and the other German. So, these two persons can speak and understand only French and German respectively — not both. You would typically need someone (an interpreter) who knows both these languages to facilitate the communication. So, the person who can facilitate this communication acts as the adapter. This pattern falls under the structural category since you would use this pattern to structure the types in our application — typically this pattern can transform one interface into another. The Gang of Four defines the 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.” Let’s dig into some code now. Consider the following two classes. public class TargetA { public void DisplayA() { Console.WriteLine("TargetA"); } } public class TargetB { public void DisplayB() { Console.WriteLine("TargetB"); } } As you can see, the two classes are incompatible — they don’t have any common base either. The following code listing shows how the adapter classes look like. public interface ITargetAdapter { void ProcessData(); } public class AdapterA : ITargetAdapter { public TargetA targetA { get; set; } public void Process() { targetA.DisplayA(); } public AdapterA(TargetA obj) { targetA = obj; } } public class AdapterB : ITargetAdapter { public TargetB targetB { get; set; } public void Process() { targetB.DisplayB(); } public AdapterB(TargetB obj) { targetB = obj; } } Note that both the adapter classes have one common interface named ITargetAdapter that these classes implement. Each of the two adapter classes has an argument constructor that accepts a reference to an object of the respective target classes. The ITargetAdapter interface contains the declaration of the Process() method. This method is implemented by both the adapter classes — these methods invoke the Display() and the respective display methods of the target classes we implemented earlier. The following code listing illustrates how you can use these adapter classes. class Program { static void Main(string[] args) { ITargetAdapter adapter = new AdapterA(new TargetA()); adapter.Process(); adapter = new AdapterB(new TargetB()); adapter.Process(); Console.Read(); } As you can see in the above code snippet, we need to pass an instance of the respective target class to the constructor of the adapter class. I’ll present discussions on more design patterns in my forthcoming posts here. The Adapter design pattern can be a good choice when you would need to invoke legacy code in your applications. You can learn more on the Adapter design pattern from this article. Related content feature What is Rust? Safe, fast, and easy software development Unlike most programming languages, Rust doesn't make you choose between speed, safety, and ease of use. Find out how Rust delivers better code with fewer compromises, and a few downsides to consider before learning Rust. By Serdar Yegulalp Nov 20, 2024 11 mins Rust Programming Languages Software Development how-to Kotlin for Java developers: Classes and coroutines Kotlin was designed to bring more flexibility and flow to programming in the JVM. Here's an in-depth look at how Kotlin makes working with classes and objects easier and introduces coroutines to modernize concurrency. By Matthew Tyson Nov 20, 2024 9 mins Java Kotlin Programming Languages analysis Azure AI Foundry tools for changes in AI applications Microsoft’s launch of Azure AI Foundry at Ignite 2024 signals a welcome shift from chatbots to agents and to using AI for business process automation. By Simon Bisson Nov 20, 2024 7 mins Microsoft Azure Generative AI Development Tools news Microsoft unveils imaging APIs for Windows Copilot Runtime Generative AI-backed APIs will allow developers to build image super resolution, image segmentation, object erase, and OCR capabilities into Windows applications. By Paul Krill Nov 19, 2024 2 mins Generative AI APIs Development Libraries and Frameworks Resources Videos