适配器模式:将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能一起工作的那些类可以在一起工作。
什么插头2口转3口,什么USB转PS2,这都算是适配器模式。说白了,就是如果有一些东西提供的接口你很像用,但是你手头没有好的接口使用它,这个就需要一个适配器,将你需要的接口转换成你所拥有的接口。这样的好处也是显而易见,就是你不用改变你现在所拥有的接口,保证你在任何地方的用法都不需要修改,然后底层的实现由适配器调用需要的接口来具体实现。Adapter模式的宗旨:保留现有类所提供的服务,向客户提供接口,以满足客户的期望。共有两类适配器模式:
(1)对象适配器模式 -- 在这种适配器模式中,适配器容纳一个它包裹的类的实例。在这种情况下,适配器调用被包裹对象的物理实体。
(2)类适配器模式 -- 这种适配器模式下,适配器继承自已实现的类(一般多重继承)
下面给出个适配器模式例子
上面例子是对象适配器模型,而类适配器模型其实就是AdapterVolt,同时继承FiveVolt,和AdapteeVolt220,通过子类调用AdapteeVolt220父类的方法来达到和对象适配器模型组合调用相同的效果.
下面说下类适配器,对象适配器的优缺点
类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。
对于类适配器,由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工作,因为继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理Adaptee的子类了。对于对象适配器,一个适配器可以把多种不同的源适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无所谓
类适配器采用“多继承”的实现方式,带来了不良的高耦合,所以一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合精神。
下面这个例子取用了 wuzhekai1985博客适配器的模式,认为用的挺巧的,可以深入探讨下
适配器(Adapter): Queue 和 Stack 两个
在实际开发中,我们也常会遇到这种接口中定义了太多的方法,以致于有时我们在一些实现类中并不是都需要的,而上面的例子很好的运用了单继承加组合的方法,适配成自己的类所需要的方法,一般的话,我们采用的是双重继承的方法来解决这类问题,即可以创建一个类Wrapper,实现接口所有方法(至于为啥要新创建个类,主要取决于子类继承纯虚类,就必须实现纯虚类中所要的纯虚函数,即接口)我们写别的类的时候,继承这个类,然后重写父类中自己要实现的方法。例子如下
调用 first method1
调用 second method2
有些地方把上面这种方法叫做接口适配器模式,这里不做深究,主要看下Deque和Method两则的关联,你会发现例子中Method1和Method2类中的调用的method方法要是Method1只调用method1,而Method2只调用method2,完全可以加一个接口中加一个method()将method1,method2方法归类起来
class Meth{
public:
vritual void method() = 0;
}
Meth 作为目标接口(Target) TempClass 就相当于需要适配的类(Adaptee)
适配器(Adapter): Method1和 Method2两个 到此发现Method完全转成Deque例子中的模式了,前提是接口方法存在一定相关性,至此适配器告一段落
下面给出个适配器模式例子
class FiveVolt
{
public:
virtual int GetVolt5() = 0;
};
class AdapteeVolt220
{
public :
int GetVolt220()
{
cout << "220v电压"<<endl;
return 220;
}
};
class AdapterVolt :public FiveVolt
{
AdapteeVolt220 mVolt220 ;
int GetVolt5()
{
int nVolt = mVolt220.GetVolt220();
printf_s("已适配成%d伏特的电压",nVolt/44);
return nVolt/44;
}
};
从代码上可以看出是 将220电压适配成5v电压,家庭标准电压220v,但是有些小电器是不需要这么高的电压的,因此需要通过电源适配器将220v转成小电器所需电压,满足小电器需要,这就是典型适配器模式
int _tmain(int argc, _TCHAR* argv[])
{
FiveVolt * mFiveVolt = new AdapterVolt();
mFiveVolt->GetVolt5();
return 0;
}
最后输出 220v电压 已适配成5伏特的电压
上面例子是对象适配器模型,而类适配器模型其实就是AdapterVolt,同时继承FiveVolt,和AdapteeVolt220,通过子类调用AdapteeVolt220父类的方法来达到和对象适配器模型组合调用相同的效果.
下面说下类适配器,对象适配器的优缺点
类适配器使用对象继承的方式,是静态的定义方式;而对象适配器使用对象组合的方式,是动态组合的方式。
对于类适配器,由于适配器直接继承了Adaptee,使得适配器不能和Adaptee的子类一起工作,因为继承是静态的关系,当适配器继承了Adaptee后,就不可能再去处理Adaptee的子类了。对于对象适配器,一个适配器可以把多种不同的源适配到同一个目标。换言之,同一个适配器可以把源类和它的子类都适配到目标接口。因为对象适配器采用的是对象组合的关系,只要对象类型正确,是不是子类都无所谓
类适配器采用“多继承”的实现方式,带来了不良的高耦合,所以一般不推荐使用。对象适配器采用“对象组合”的方式,更符合松耦合精神。
模式中的角色
1 目标接口(Target):客户所期待的接口。目标可以是具体的或抽象的类,也可以是接口。(上面例子就是FiveVolt)
2 需要适配的类(Adaptee):需要适配的类或适配者类。(AdapteeVolt220)
3 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口。(AdapterVolt)
下面这个例子取用了 wuzhekai1985博客适配器的模式,认为用的挺巧的,可以深入探讨下
//双端队列
class Deque
{
public:
void push_back(int x) { cout<<"Deque push_back"<<endl; }
void push_front(int x) { cout<<"Deque push_front"<<endl; }
void pop_back() { cout<<"Deque pop_back"<<endl; }
void pop_front() { cout<<"Deque pop_front"<<endl; }
};
//顺序容器
class Sequence
{
public:
virtual void push(int x) = 0;
virtual void pop() = 0;
};
//栈
class Stack: public Sequence
{
public:
void push(int x) { deque.push_back(x); }
void pop() { deque.pop_back(); }
private:
Deque deque; //双端队列
};
//队列
class Queue: public Sequence
{
public:
void push(int x) { deque.push_back(x); }
void pop() { deque.pop_front(); }
private:
Deque deque; //双端队列
};
使用方式如下:
int main()
{
Sequence *s1 = new Stack();
Sequence *s2 = new Queue();
s1->push(1); s1->pop();
s2->push(1); s2->pop();
delete s1; delete s2;
return 0;
}
例子中
目标接口(Target):Sequence 需要适配的类(Adaptee):Deque适配器(Adapter): Queue 和 Stack 两个
在实际开发中,我们也常会遇到这种接口中定义了太多的方法,以致于有时我们在一些实现类中并不是都需要的,而上面的例子很好的运用了单继承加组合的方法,适配成自己的类所需要的方法,一般的话,我们采用的是双重继承的方法来解决这类问题,即可以创建一个类Wrapper,实现接口所有方法(至于为啥要新创建个类,主要取决于子类继承纯虚类,就必须实现纯虚类中所要的纯虚函数,即接口)我们写别的类的时候,继承这个类,然后重写父类中自己要实现的方法。例子如下
class Medthod {
public:
vritual void method1() = 0;
vritual void method2() = 0;
}
class TempClass :public Medthod{
public:
void method1(){}
void method2(){}
}
class Medthod1 : public TempClass
{
public:
void method1(){
cout <<"调用 first method1" <<endl;
}
}
class Medthod2 : public TempClass
{
public:
void method2(){
cout <<"调用 second method2" <<endl;
}
}
int _tmain(int argc,_TCHAR* argv[])
{
Medthod * source1 = new Medthod1();
Medthod * source2 = new Medthod2();
source1.method1();
source1.method2();
source2.method1();
source2.method2();
return 0;
}
最后输出;
调用 first method1
调用 second method2
有些地方把上面这种方法叫做接口适配器模式,这里不做深究,主要看下Deque和Method两则的关联,你会发现例子中Method1和Method2类中的调用的method方法要是Method1只调用method1,而Method2只调用method2,完全可以加一个接口中加一个method()将method1,method2方法归类起来
class Meth{
public:
vritual void method() = 0;
}
Meth 作为目标接口(Target) TempClass 就相当于需要适配的类(Adaptee)
适配器(Adapter): Method1和 Method2两个 到此发现Method完全转成Deque例子中的模式了,前提是接口方法存在一定相关性,至此适配器告一段落