Wednesday, 1 September 2010

C++ example for Adapter Design Pattern

The Adapter pattern is used to convert the programming interface of one class into that of another. We use adapters whenever we want unrelated classes to work together in a single program. The concept of an adapter is thus pretty simple; we write a class that has the desired interface and then make it communicate with the class that has a different interface.

There are two ways to do this: by inheritance, and by object composition. In the first case, we derive a new class from the nonconforming one and add the methods we need to make the new derived class match the desired interface. The other way is to include the original class inside the new one and create the methods to translate calls within the new class. These two approaches are termed as class adapters and object adapters respectively.

The frequency of usage of adapter pattern is medium high.

Example of Adapter pattern as follows:



//Program tested on Microsoft Visual Studio 2008 - Zahid Ghadialy
//Adapter is part of Structural Patterns
//Structural Patterns deal with decoupling the interface and implementation of classes and objects
//Adapter pattern is used to convert the programming interface of one class into that of another.

//We Take an example where chemical compound objects accesses the databank
//through an Adapter Interface

#include<iostream>
#include<string>

using namespace
std;

//The 'Target' class
class Compound
{

public
:
Compound(string chemical):chemical_(chemical){}
virtual
~Compound() {};
void
Display()
{

cout << "\nCompound: " << chemical_ << "----------------" << endl;
}

protected
:
string chemical_;
float
boilingPoint_;
float
meltingPoint_;
double
molecularWeight_;
string molecularFormula_;
private
:
Compound(); //disallow default constructor
};

//The 'Adaptee' class
class ChemicalDatabank
{

public
:
virtual
~ChemicalDatabank() {};
//The databank 'legacy API'
float GetCriticalPoint(string compound, string point)
{

string lowerCompound = toLowerString(compound);
//Melting Point
if (point == "M")
{

if
(_stricmp(lowerCompound.c_str(), "water") == 0)
return
0.0;
else if
(_stricmp(lowerCompound.c_str(), "benzene") == 0)
return
5.5;
else if
(_stricmp(lowerCompound.c_str(), "ethanol") == 0)
return
(float) -114.1;
else
return
0.0;
}

//Boiling point
else
{

if
(_stricmp(lowerCompound.c_str(), "water") == 0)
return
(float) 100.0;
else if
(_stricmp(lowerCompound.c_str(), "benzene") == 0)
return
(float) 80.1;
else if
(_stricmp(lowerCompound.c_str(), "ethanol") == 0)
return
(float) 78.3;
else
return
0.0;
}
}


string GetMolecularStructure(string compound)
{

string lowerCompound = toLowerString(compound);

if
(_stricmp(lowerCompound.c_str(), "water") == 0)
return
"H2O";
else if
(_stricmp(lowerCompound.c_str(), "benzene") == 0)
return
"C6H6";
else if
(_stricmp(lowerCompound.c_str(), "ethanol") == 0)
return
"C2H5OH";
else
return
"";
}


double
GetMolecularWeight(string compound)
{

string lowerCompound = toLowerString(compound);

if
(_stricmp(lowerCompound.c_str(), "water") == 0)
return
18.015;
else if
(_stricmp(lowerCompound.c_str(), "benzene") == 0)
return
78.1134;
else if
(_stricmp(lowerCompound.c_str(), "ethanol") == 0)
return
46.0688;
else
return
0.0;
}

private
:
//Helper function
string toLowerString(string& input)
{

int
length = input.length();
string output;
for
(int i = 0; i < length; i++)
{

output += tolower(input[i]);
}

return
output;
}
};


//The 'Adapter' class
class RichCompound : public Compound
{

public
:
RichCompound(string name) : Compound(name)
{

bank_ = new ChemicalDatabank();
}

virtual
~RichCompound()
{

delete
bank_;
}

void
Display()
{

boilingPoint_ = bank_->GetCriticalPoint(chemical_, "B");
meltingPoint_ = bank_->GetCriticalPoint(chemical_, "M");
molecularWeight_ = bank_->GetMolecularWeight(chemical_);
molecularFormula_ = bank_->GetMolecularStructure(chemical_);

Compound::Display();
cout << " Formula : " << molecularFormula_ << endl;
cout << " Weight : " << molecularWeight_ << endl;
cout << " Melting Pt : " << meltingPoint_ << endl;
cout << " Boiling Pt : " << boilingPoint_ << endl;
}

private
:
ChemicalDatabank* bank_;
RichCompound(); //dis-allow default constructor
};

int
main()
{

Compound unknown("Unknown");
unknown.Display();

RichCompound water("Water");
water.Display();

RichCompound benzene("Benzene");
benzene.Display();

RichCompound ethanol("Ethanol");
ethanol.Display();

RichCompound zahid("Zahid");
zahid.Display();

return
0;
}






The output is as follows:



For more details, please see:

http://www.dofactory.com/Patterns/PatternAdapter.aspx
http://www.patterndepot.com/put/8/adapter.pdf

2 comments:

  1. Hey, great post, first of all.

    One comment..._stricmp is a Visual Studio only command...you might want to mention that in your post (I was compiling under a Unix based system.

    ReplyDelete
  2. Hi, This is a good example. Is it a class adaptor?

    ReplyDelete