适配器类是一种接口类类型,为其它现有面向对象类型提供封装器,也就是说它将一个类的接口转换成另一个类接口的样子。在有些情况下,某个类可能表示了我们需要的数据且包含对数据的基本操作,但我们需要将这个类的接口调整或重新定义。适配器的两种实现途径,第一种是使用继承,第二种是使用模板将类封存。
1. 继承方式
先看下面两个类:
#include<iostream>
class MathematicalExpression
{
public:
MathematicalExpression(const std::string x) {
expression_ = x;
}
void GetExpression(std::string& x){ x = expression_;}
void ToKenizeExpression(){}
protected:
std::string expression_;
};
class Sentence: private MathematicalExpression{
public:
Sentence(const std::string s):
MathematicalExpression(s){}
void GetSentence(std::string& s){
GetExpression(s);
}
void ParseSentence(){
ToKenizeExpression();
}
};
MathematicalExpression类表示的数据刚好是我们需要的一个类,它有一个string类且有一个将string类解析的操作函数,不过,我们现在把它用在一个自然语言解析的项目中,需要一个string类组件且同时需要与ToKenizeExpression()函数功能相同的解析操作,在这里它并不是一个数学表达式,这时候我们就可以使用接口类来调整MathematicalExpression类的接口使它具有我们应用场合需要的接口。因此我们从MathematicalExpression类派生了一个名为Sentence的类,使其操作更吻合我们使用的具体场合,我们只是重命名了基类的成员函数,不添加任何新数据成员或者成员函数(尽管可以这样做)。我们不希望用户直接操作GetExpression和ToKenizeExpression,一个适配器类可能只选择修改被转换类的部分成员函数,所以我们使用了私有继承提供了一定程度的安全性。
2. 模板将类封存方式
下面来看一下STL里的stack声明:
template<class Container>
class stack{
friend bool operator ==(const stack<Container>& x,
const stack<Container>& y);
friend bool operator <(const stack<Container>& x,
const stack<Container>& y);
public:
typedef Container::value_type value_type;
typedef Container::size_type size_type;
protected:
Container c;
public:
bool empty()const{return c.empty();}
size_type size()const {return c.size();}
value_type& top(){return c.back();}
const value_type& top()const{return c.back();}
void push(const value_type& x){c.push_back(x);}
void pop(){c.pop_back();}
};
stack类为标准模板库中的list、vector、deque容器提供了一个新的公共接口,例如:stack<vector> Stack。它提供了一个对于堆栈语义正确的类,堆栈是一种LIFO(后进先出)的数据结构。在这里类c是一个矢量容器,stack类只是用于调整其它类的接口,与Sentence一样,被修改类的成员函数不能通过stack类的非成员来访问。这两种情况下,接口类都被可以访问修改类,但对于外界,其访问权是有选择性的。通过使用适配技术,接口类可以使用修改后的实现来预定所需要的访问。注:只是重命名适配类的成员函数,因此使用C++内联功能,重命名的开销可以降到最低点。