例子
我们的网管告警亮灯:是否有告警需要从另一个公司的网管中获取,我们的接口是:bool IsAlarming,另一个公司的接口是:bool GetAlarm()
定义
适配器模式:将一个类的接口转换成客户希望的另外一个接口。适配器模式使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
- 通过继承进行的适配,叫做类适配器;通过关联关系进行的适配,叫做对象适配器。二者在实际项目中都会经常用到,由于对象适配器是通过类间的关联关系进行耦合的,因此在设计时就可以做到比较灵活,而类适配器就只能通过覆写源角色的方法进行扩展,在实际项目中,对象适配器使用到场景相对较多。
优点
- 1.可以让两个没有任何关系的类在一起运行,只要适配器这个角色能够搞定他们就成。
- 2.增加了类的透明性。(我们访问target目标角色,但是具体的实现都委托给了源角色,而这些对高层次模块是透明的,也是它不需要关心的)
- 3.提高了类的复用度(源角色在原有的系统中还是可以正常使用,而在目标角色中也可以充当新的演员)
- 4.灵活性非常好(类似一个灵活的构件,想用就用,不想用就卸载)
注意事项
- 1.在详细设计阶段不要考虑适配器模式,它不是为了解决还处在开发阶段的问题,而是解决已经投产的项目问题。
- 2.项目一定要遵守依赖倒置原则和里氏替换原则,否则即使在适合使用适配器的场合下,也会带来非常大的改造。
上文中提到的两个原则
里氏替换原则:
- 子类型必须能够替换掉它们的父类型
即:一个软件实体如果使用的是一个父类的话,那么一定适用于其子类,而且它察觉不出父类对象和子类对象的区别。也就是说,在软件里面,把父类都替换成它的子类,程序的行为没有变化。
依赖倒置原则:
- 1.高层模块不应该依赖于低层模块。两个都应该依赖抽象。
- 2.抽象不应该依赖细节,细节应该依赖于抽象。
即:要针对接口编程,不要对实现编程。不管高层模块还是低层模块,他们都依赖于抽象,具体一点就是接口或抽象类,只要接口是稳定的,那么任何一个的更改都不用担心其他受到影响,这就使得无论高层模块还是低层模块都可以很容易地被复用。
#include <iostream>
using namespace std;
class Target
{
public:
virtual void Request()
{
cout<<"普通的请求"<<endl;
}
};
class Adaptee
{
public:
void SpecificalRequest()
{
cout<<"特殊请求"<<endl;
}
};
class Adapter :public Target
{
private:
Adaptee* ada;
public:
virtual void Request()
{
ada->SpecificalRequest();
Target::Request();
}
Adapter()
{
ada=new Adaptee();
}
~Adapter()
{
delete ada;
}
};
客户端:
int main()
{
Adapter * ada=new Adapter();
ada->Request();
delete ada;
return 0;
}