学习适配器模式的时候看到一个哥们说的一句话,觉得很有理:学习就像煮水,断断续续的烧,水永远不会沸腾。
现在的笔记本与大多外设交互都是usb接口,但不是所有外设都能直接通过usb接口连接到电脑,比如老式键盘鼠标,它们都是ps2接口的,为了使用这些外设,我们要使用转接器,例如ps2-usb转接口。其实这些转接器,包括笔记本电源电压的转换器,这些都可以叫做适配器。他们会把本不能使用的事物转换成我们期望的制式提供给我们使用。
在写代码的时候也会出现这种情况,有一些类明明实现了我们想要使用的功能,但是由于其接口不符合我们当前通用的接口规范,导致我们无法直接使用(与其他厂家集成、在旧产品上进行二次开发、甚至在一款产品的开发过程中两个研发人员缺少必要的协商都有可能出现这种情况),我们拿上面的ps2鼠标说事儿,先来实现常规下的代码。
//这个是usb通用接口
public interface IUsb {
public String getUsbDeviceDescription();
}
//这个是移动硬盘类的实现
public class RemovableHardDisk implements IUsb{
public String getUsbDeviceDescription()
{
return "I am a removable hard disk.";
}
}
//这个是ps2鼠标类的实现
public class Ps2Mouse {
public String getDecription() {
return "I am a ps2 mouse.";
}
}
//应用场景只能这样使用ps2鼠标
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
IUsb usb = new RemovableHardDisk();
String strDescription = usb.getUsbDeviceDescription();
System.out.println(strDescription);
Ps2Mouse mouse = new Ps2Mouse();
strDescription = mouse.getDecription();
System.out.println(strDescription);
}
}
上面的代码可以看到,Ps2Mouse 鼠标和其他通用usb设备有一些功能是一样的,然而Ps2Mouse 类是不可变的,而为了适应这个Ps2Mouse 类就改变所有usb设备的接口也不现实,那么我们有没有什么方法也能把Ps2Mouse 类像IUsb接口一样使用?答案就是适配器模式。
适配器模式:将一个类的接口转换成用户希望的接口规范,使得这个原本因为接口不兼容而不能和其他类一起工作的类可以一起工作。
一、特征
1:转换,在不兼容的类的基础上进行封装,使其可以以预期的接口规范被调用。封装的形式有两种,一种是Adapter在遵循预期的接口规范的基础上继承这个不兼容的类,在接口实现时调用基类函数,这种方式叫做类适配器。一种是Adapter在遵循预期的接口规范的基础上定义一个此不兼容类的变量,在接口实现时调用这个变量的函数,这种方式叫做对象适配器。
二、实现
由图可知适配器模式包含一下三个角色:
1:Target(目标抽象类):目标抽象类定义客户所需的接口,可以是一个抽象类或接口,也可以是具体类。在类适配器中,由于java/C#语言不支持多重继承,所以只能是接口,在c++中,可以是带虚函数的基类。
2:Adapter(适配器类):它可以调用另一个接口,作为一个转换器,对Adaptee和Target进行适配。它是适配器模式的核心。
3:Adaptee(适配者类):适配者即被适配的角色,它定义了一个已经存在的接口,这个接口需要适配,适配者类包好了客户希望的业务方法。
我们来看看ps2鼠标怎么当成usb设备用。
//这个是usb通用接口
public interface IUsb {
public String getUsbDeviceDescription();
}
//这个是移动硬盘类的实现
public class RemovableHardDisk implements IUsb{
public String getUsbDeviceDescription()
{
return "I am a removable hard disk.";
}
}
//这个是ps2鼠标类的实现
public class Ps2Mouse {
public String getDecription() {
return "I am a ps2 mouse.";
}
}
//这个是ps2转usb的转接口,也就是适配器
public class Ps2Adapter extends Ps2Mouse implements IUsb{
public String getUsbDeviceDescription()
{
return getDecription();
}
}
//使用场景就会变的很简单
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
IUsb usb = new RemovableHardDisk();
System.out.println(usb.getUsbDeviceDescription());
usb = new Ps2Adapter();
System.out.println(usb.getUsbDeviceDescription());
}
}
我们想要使用一个已经存在的类的功能,而这个类不符合我们现有的接口规范,这个时候我们可以使用适配器模式,当然其他应用场景中也可能使用到,例如我们想要实现某个接口的部分功能,某些其他功能我们不想实现,这时候我们可以用一个适配器实现一些缺省的功能,而需要实现的功能我们可以在具体业务类中实现。