【转】设计模式学习笔记(6)-适配器
原文链接:http://lecoding.com/articles/167.html
适配器(Adapter)模式是准备学的第一个结构型模式。结构型模式涉及到如何组合类和对象以获得更大的结构。主要利用到面向对象编程中的组合和继承。
在实际编程当中,我们经常遇到这种情况,某一个类与另一个类功能很相似,但又不能抽象出一个接口来继承;或者想要复用一个现成的、已经写好的类,但该类与现有代码中的接口不兼
容,无法直接使用。这些情况下我们就可以考虑使用适配器模式。适配器这个词来自于实际生活当中,如市电使用的是交流点而有的用电器使用的是直流电,这时就必须使用电流适配器来将
交流电转换为直流电。程序设计当中的将一个接口转化为另一个接口的类就叫做Adapter,将要被转化的接口称为Adaptee,转化成的端口称为Target。
单纯说起来可能并不是很清楚,我们举个例子吧。我们有两辆车,分别是小汽车(Car)和自行车(Bike),虽然从外观上看来差距很大但他们都属于车类。Car中有一个start方法表示启动引擎,
Bike中有个ride方法表示开始骑车。现在我们想要乘车,但是我只会骑自行车(只认识ride方法),不会开车(不认识start)方法,怎么办?定义一个Adapter。
代码很简单,如下:
Car类:
|
1
2
3
4
5
6
7
8
|
class Car {public: virtual void start() { cout << "Engine start!" << endl; }}; |
Car中的start方法输出 “Engine start!” 语句。
Bike类:
|
1
2
3
4
5
6
7
8
|
class Bike {public: virtual void ride() { cout << "Ride a bike!" << endl; }}; |
Bike类中的ride方法输出”Ride a bike!”语句
Adapter类
|
1
2
3
4
5
6
7
8
|
class Adapter : public Bike, private Car {public: void ride() { Car::start(); }}; |
这里要注意了,Adapter多重继承了Bike和Car类,Adapter类应该采用公共方式继承Target(Bike)类,并且用私有方式继承Adaptee类,因此,Adapter类应该是Target的子类型,但不
是Adaptee的子类型。Adapter类中重载了ride方法,这里只是简单地调用了Car类中的start方法,当然也可以做一些外围的处理工作。
主方法里这样写道:
|
1
2
|
Bike* bike = new Adapter;bike->ride(); |
最终输出:
|
1
|
Engine start! |
我们调用的是bike中的ride方法,但却输出了Car中的字符串,这个过程对于执行者来说是透明的,他只需把汽车当成自行车来骑就行了,并且没有意识到他驾驶的其实是汽车。
上面这个示例很简单,它采取的是继承方式实现适配,而在实际编程当作继承往往不如组合灵活,那么适配器模式能否使用组合方式实现呢?答案是可以的。
简单的类图如下:
这里Adapter仅继承了Target,并没有继承Adaptee,Adaptee作为一个成员变量存储在Adapter当中。
改变一下Adapter的代码:
|
1
2
3
4
5
6
7
8
9
10
11
|
class Adapter : public Bike{private: Car* _car;public: Adapter(Car *car) : _car(car){} void ride() { _car->start(); }}; |
这里的构造函数有一个Car* 类型的参数。
主方法里这样调用:
|
1
2
|
Bike* bike = new Adapter(new Car);bike->ride(); |
输出结果跟刚才是一样的。
最基本的适配器就是这两种了。
现在讨论几个概念:
双向适配器
所谓双向适配器是指这个适配器可以同时适配两个类或对象,即一个骑自行车的人可以按照骑自行车的方式来发动汽车,另一个开汽车的人同时也可以按照开汽车的方式来骑自行车。这个实
现还是很简单的。
对于类:
|
1
2
3
4
5
6
7
8
9
10
11
12
|
class DualAdapter : public Bike, public Car{public: void ride() { Car::start(); } void start() { Bike::ride(); }}; |
对于对象:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
|
class DualAdapter2 : public Bike {private: Car* _car; Bike* _bike;public: DualAdapter2(Car* car, Bike* bike) : _car(car), _bike(bike){} void ride() { _car->start(); } void start() { _bike->ride(); }}; |
这里要构造函数要传两个对象。
可插入式适配器(Pluggable Adapter)
所谓可插入式适配器,是指为某个类找一个最小操作集,即为Adaptee找到一个“窄”的接口。如一个比较大的类,其中有很多方法,但只有一个方法需要适配,怎么办?做成可插入适配器。
将适配器插在Adaptee中,就是这个意思。这种适配器实现起来有三种方式:
1、使用抽象操作
在对类的使用时使用抽象操作,这里类似于抽象工厂模式,即将具体的实现方式交给子类
2、使用代理对象
将所有有可能涉及到具体对象的操作交给一个代理接口,另外该接口实现一个具体类(Adapter)来完成具体操作,最终将具体类的结果返回给Clinet
3、参数化适配器
这主要应用C++的函数指针或Java中的反射等机制,直接将具体操作作为一个参数传给调用对象。
最后来看一下Adapter模式的适用性
- 想使用一个已经存在的类,而它的接口不符合你的要求
- 想创建一个可以复用的类,该类可以与其它不相关的类或不可预见的类(即那些接口可能不一定兼容的类)协同工作
- (仅适用于对象Adapter)想使用一些已经存在的子类,但是不可能对每一个都进行子类化以匹配它们的接口。对象适配器可以适配它的父类接口
posted on 2013-03-05 14:05 TheKingOfKingFish 阅读(120) 评论(0) 收藏 举报

浙公网安备 33010602011771号