设计模式——适配器模式
适配器模式是作为两个不兼容的接口之间的桥梁,这种类型的设计模式属于结构模式,它主要作用是将一个类的接口转换成客户希望的另外一个接口,适配器模式使得原本由于接口不兼容而不能在一起工作的那些类可以一起工作。在网上看了各位大牛写的适配器模式的文章,用各种例子进行举例的,可见适配器模式可以解决许多接口不配的问题。我们这里用电脑、内存卡、读卡器来举例。电脑有USB接口,内存卡的接口是SD总线模式,需要将内存卡插到读卡器中再插到电脑上,供电脑读写内存卡数据。这个读卡就是适配器。
//定义一个USB接口
public interface Usb {
//USb接口可以读取数据
public String readData();
//Usb接口也可以写入数据
public void writeData(String data);
}
//计算机类
public class Computer {
//计算机可以通过USB接口读取数据
public String readData(Usb usb) {
return usb.readData();
}
//计算机可以往Usb中写入数据。
@Override
public void writeData(USb usb,String data) {
usb.setData(data);
}
}
//现在我们有一个内存卡
public class SdCard {
//内存卡中存的数据
private String data = "SdCard Data";
//读取内存卡数据的接口
public String getData() {
return data;
}
//向内存卡写入数据的接口
public void setData(String data) {
this.data = data;
}
}
//内存卡是没有Usb接口的,所以计算机不能直接读取内存卡数据,这就需要我们定义一个有Usb接口的适配器。
public class SdCardAdapter implements Usb {
private SdCard sd;
//构造函数传入一个内存卡,相当于现实中将内存卡插入到读卡器。
public SdCardAdapter(SdCard sd) {
this.sd = sd;
}
//读卡器知道怎么读取内存卡中的数据。
@Override
public String readData() {
return sd.getData();
}
//读卡器往内存卡中写数据。
@Override
public void writeData(String data) {
sd.setData(data);
}
}
//调用示例
public class Demo(){
public static void main(String [] args){
//实例化内存卡
SdCard sd = new SdCard();
//实例化读卡器。
SdCardAdapter sdAdapter = new SdCardAdapter(sd);
//实例化计算机
Computer computer =new Computer();
//计算机通过读卡器读取内存卡中的数据
System.out.println("Sd Card Data is " + computer.readData(sdAdapter));
//往内存卡中写入新的数据。
computer.writeData(sdAdapter, "新写入的数据");
//读取刚写入的数据
System.out.println("Sd Card Data is " + computer.readData(sdAdapter));
}
}
c++的实现
//定义Usb接口
class Usb {
public:
virtual std::string readData()=0;
virtual void writeData(const std::string& data) =0;
};
//计算机类
class Computer {
public:
//计算机读取USB设备的数据
std::string readData(Usb& usb) {
return usb.readData();
}
//计算机往USB设备写数据
void writeData(Usb& usb, const std::string data) {
usb.writeData(data);
}
};
//内存卡类
class SdCard {
public:
//读取内存卡中的数据
std::string getData() {
return data;
}
//向内存卡中写入数据
void setData(const std::string data) {
this->data = data;
}
private:
//内存卡中存放的数据
std::string data = "默认数据";
};
//读卡器类,实现USB接口
class SdCardAdapter : public Usb {
public:
SdCardAdapter(SdCard* sd) {
this->sd = sd;
}
//读取内存卡中的数据
std::string readData() override {
return sd->getData();
}
//向内存卡写入数据
void writeData(const std::string& data) override {
sd->setData(data);
}
private:
SdCard* sd;
};
int main(){
//实例内存卡
SdCard sd;
//实例化读卡器
SdCardAdapter adapter(&sd);
//实例化计算机
Computer computer;
//读取内存卡数据
std::cout << "Sd Card Data is :" << computer.readData(adapter) << std::endl;
//写入内存卡数据
computer.writeData(adapter, "new Data");
std::cout << "Sd Card Data is :" << computer.readData(adapter) << std::endl;
}
以上适配器有一个SdCard类型的私有变量,适配器技有内存卡对象,这种方式被称为对象的适配器模式,还有一种通过继承实的的适配器称为类的适配器模式
Java代码
public class SdCardAdapter2 extends SdCard implements Usb {
@Override
public String readData() {
return getData();
}
@Override
public void writeData(String data) {
this.setData(data);
}
}
C++代码
class SdCardAdapter2 : public Usb, SdCard {
public:
//读取内存卡中的数据
std::string readData() override {
return getData();
}
//向内存卡写入数据
void writeData(const std::string& data) override {
setData(data);
}
};
除了作为接口匹配来使用,在写框架时,使用适配器可以给使用框架的用户更多灵活,比如android中的ListView 和RecyclerView 留给开发人员实现适配器,从而可以让开发人员方便的实现各种需求。
优点:
1、可以让任何两个没有关联的类一起运行。
2、提高了类的复用。
3、增加了类的透明度。
4、灵活性好。
缺点:
1、过多地使用适配器,会让系统非常零乱,不易整体进行把握。比如,明明看到调用的是 A 接口,其实内部被适配成了 B 接口的实现,一个系统如果太多出现这种情况,无异于一场灾难。因此如果不是很有必要,可以不使用适配器,而是直接对系统进行重构。
2.由于 JAVA 至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。