Working with the Adapter design pattern

Leverage the Adapter design pattern to map incompatible interfaces, increase code coverage, and reduce complexities in designs

Adapter design pattern

Adapter design pattern

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.

This article is published as part of the IDG Contributor Network. Want to Join?

From CIO: 8 Free Online Courses to Grow Your Tech Skills
Notice to our Readers
We're now using social media to take your comments and feedback. Learn more about this here.