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
Hey, great post, first of all.
ReplyDeleteOne 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.
Hi, This is a good example. Is it a class adaptor?
ReplyDelete