Adapter Design Pattern: Structural Patterns

Share the Article

What

Adapter design pattern is a type of Structural Pattern. This pattern enables adaptation of an incompatible interface to client’s requirement.

In real world applications, we may already have existing classes with good features. However, due to incompatibility in interfaces, we are not able able to use them. An example of incompatible interfaces from real life is, that our electrical equipment has 3 pin plug but the main supply has only 2 pin socket. Therefore, we use a 3 pin to 2 pin electrical adaptor. The Adapter design pattern works on the same principle. It provides an opportunity to adapt different class interfaces to clients demand.

Why

Let us try to understand the need for Adapter by taking an example of very simple application. This application shall have a job to create and show aComputer.

Simple Example without using Adapter Design Pattern

In this case, the user is having an option to select keyboard, mouse, processor and screen. Therefore, our client may use following interfaces for creating and displaying computer details.

void createComputer(string keyborad, string mouse, string processor, string screen); void showComputer();

Below is the sample code, depicting client interaction with Computer class. It also explains, how the Client create and display Computer components.

#include<iostream> // Main header #include<string> // for string using namespace std; class Computer { private: string m_KeyBoard; string m_Mouse; string m_Processor; string m_Screen; public: void createComputer(string keyboard, string mouse, string processor, string screen) { m_KeyBoard=keyboard; m_Mouse=mouse; m_Processor=processor; m_Screen = screen; } void showComputer() { cout<<"Computer created with "<<endl; cout<<" keyboard "<<m_KeyBoard<<endl; cout<<" Mouse "<<m_Mouse<<endl; cout<<" Processor "<<m_Processor<<endl; cout<<"Screen Type "<<m_Screen<<endl; } }; int main() //client code { Computer *c1 = new Computer; c1->createComputer( "wired", "wireless", "Single Core", "Non touch"); c1->showComputer(); delete c1; }

As seen above, the client (main function) is happily using Computer class. Now, lets see down the line, when Smart Computer Class also came into the Market. A problem may happen when our Client wants to use that.

Problem with Smart Computer is that it is having only option to select keyboard, processor and mouse but not screen. This is because, the Smart Computer is only supports “Touch” Screen.

In this example, the Smart Computer going to expose an interface which is not compatible with Client’s code.

class SmartComputer { private: string m_KeyBoard; string m_Mouse; string m_Processor; public: void buildComputer(string keyboard, string mouse, string processor) { m_KeyBoard=keyboard; m_Mouse=mouse; m_Processor=processor; } void displayComputer() { cout<<"Basic Computer created with "<<endl; cout<<" keyboard "<<m_KeyBoard<<endl; cout<<" Mouse "<<m_Mouse<<endl; cout<<" Processor "<<m_Processor<<endl; }

Therefore, our Client shall not use the new SmartComputer Class. Please note, that SmartComputer is having buildComputer( ) and NOT createComputer( ).

Finally, we need to adapt, the Client code in several places. Only after this, the client can use SmartComputer. Sometimes, the clients are so much tightly coupled to rest of world that adaptation is not at all possible.

For all above problems, we have solution as Adapter Design Pattern. This will solve above problems very easily without not much impacting client. It seems to be a best fit for above issues.

How

Let us try to adapt above application so that Client can use Smart Computer for its needs.

We need to follow below specific rules for adapting incompatible interfaces of Smart Computer class :

Create an abstract Base class “Computer”

Firstly, the client code understands “Computer” Class interface. This interface contains createComputer( ) and show Computer( ) functions in it. Therefore, design a Base class with pure virtual functions to make an interface.

class Computer { public: virtual void createComputer(string keyboard, string mouse, string processor, string screen) = 0; virtual void showComputer() = 0; };

Create an Adapter class

The adapter class shall derive from abstract base class “Computer”.

class AdapterSmartComputer: public Computer

Use SmartComputer (Adaptee) inside AdapterSmartComputer (Adaptee)

Below is the snippet with composition.

class AdapterSmartComputer: public Computer { SmartComputer *b1; };
Adapter Design Pattern UML Diagram

Same Example using Adapter Design Pattern

Below is the sample application depicting how Smart Computer Class is adapted to the client’s needs.

#include<iostream> //main header #include<string> //for strings using namespace std;//for namespace //The Adaptee class class SmartComputer { private: string m_KeyBoard; string m_Mouse; string m_Processor; public: void buildComputer(string keyboard, string mouse, string processor) { m_KeyBoard=keyboard; m_Mouse=mouse; m_Processor=processor; } void displayComputer() { cout<<"Basic Computer created with "<<endl; cout<<" keyboard "<<m_KeyBoard<<endl; cout<<" Mouse "<<m_Mouse<<endl; cout<<" Processor "<<m_Processor<<endl; } }; //Base Client compatible with client's requirement class Computer { public: virtual void createComputer(string keyboard, string mouse, string processor, string screen)=0; virtual void showComputer() = 0; }; //Adapter Class class AdapterSmartComputer:public Computer { private: SmartComputer *b1; public: AdapterComputer() { b1 = new BasicComputer; } void createComputer(string keyboard, string mouse, string processor, string screen) { b1->buildComputer(keyboard,mouse,processor); } void showComputer() { b1->DisplayComputer(); cout<<"Screen "<<"Legacy Screen"<<endl; } ~AdapterComputer() { delete b1; } }; int main() //client's code { Computer *c1 = new AdapterSmartComputer; //only change c1->createComputer("wired", "wireless", "Single Core", "Legacy Screen"); c1->showComputer(); delete c1; }

As seen above, now with Adapter Design pattern we have adapted Smart Computer to client’s need. We have created AdapterSmartComputer class which has same interfaces as required by the client. Inside AdapterSmartComputer, we have called respective functions of the SmartComputer having new interface. Therefore, with the above approach, there is almost no change in SmartComputer as well as client’s code.

Pros

  1. Make incompatible interfaces compatible to client.
  2. Enhance existing classes for widespread usage.

Cons

  1. Code becomes complex with adapter class hierarchy.

Main Funda: The adapter design pattern enables the use of class with incompatible interface.

Advanced C++ Topics

Abstract Factory Design Pattern
Singleton Design Pattern
Factory Method Design Pattern
Builder Design Pattern
Thread Synchronization with Mutex
How std::forward( ) works?
How std::move() function works?
What is reference collapsing?

Share the Article

Leave a Reply

Your email address will not be published. Required fields are marked *