适配器模式
适配器模式是结构型模式介绍的第一个设计模式
对象适配器
适配器模式是解决接口转化的问题。
就好像是日常生活中使用的插口转化器
如上所示,假如我们需要使用USB接口的移动硬盘,但是我们的手机只有一个Type-C的接口,现在我们就要使用一个适配器解决接口转化的问题。
示例代码:
首先定义一个接口,例如USB接口,如果某个类实现了USB接口便可认为这个类有一个USB的接口来实现USB功能(传输数据)
interface USB{
public void transferData();
}
接下来创建一个类实现这个接口,例如我们有一个u盘 ,u盘上面恰好有一个usb的接口
class USBDrive implements USB{
@Override
public void transferData() {
System.out.println("U盘正在传输数据");
}
}
然后定义适配器
class USBTypeCAdapter{
private USB usb;
public USBTypeCAdapter(USBDrive usb){
this.usb = usb;
}
@Override
public void transferData() {
usb.transferData();
}
}
客户端调用:
public class AdapterPattern {
public static void main(String[] args) {
USBDrive usbDrive = new USBDrive();
USBTypeCAdapter usbTypeCAdapter = new USBTypeCAdapter(usbDrive);
usbTypeCAdapter.transferData();
}
}
可以看到,我们最后使用的是usbTypeCAdapter的数据传输,而不是直接使用usbDriver的传输
同时我们可以改造一下,令usbTypeCAdapter实现一个 叫做TypeC的接口。
class USBTypeCAdapter implements TypeC{...}
客户端使用TypeC类型引用接收对象的引用
public static void main(String[] args) {
USBDrive usbDrive = new USBDrive();
TypeC usbTypeCAdapter = new USBTypeCAdapter(usbDrive);
usbTypeCAdapter.transferData();
}
我们更可以直观发现,现在我们客户端可以认为使用typeC的接口而不是Usb的接口了
如上,我们将一个对象通过适配器的包装,可以通过这个对象类没有实现的接口进行调用
类适配器模式
对象适配器通常将实例化对象进行包装,但是类适配器并不需要进行示例化,而是在类上直接进行包装。
那么我们思考如果完成这种功能呢? 我们知道类的继承,自类可以继承父类的功能(除非final修饰),如果我们定义了一个子类(适配器类),他继承了适配器需要的接口(需求接口),并且继承了父类,那么他就是父类的一个适配器类了。因为我们在重写接口方法的时候,可以直接调用父类的方法,相当于将父类的方法进行了进一步封装。
我们来看一个示例
首先定义一个适配器
interface Adapter{
void printDate();
}
接下来定义需要被适配器修饰的类,也就是上述的父类
class DateInfo{
public static String getDate(){
return new Date().toString();
}
}
接下来完成适配器类
class DateAdapter extends DateInfo implements Adapter{
@Override
public void printDate() {
System.out.println(
"当前时间为:"
+getDate()
);
}
}
客户端调用
public class ClassAdapterPattern {
public static void main(String[] args) {
new DateAdapter().printDate();
}
}
类适配器与对象适配器的比较
我们看起来,对象适配器仿佛是将一个个示例的对象进行包装。而类适配器是静态地在类中使用方法进行包装。
在平时仍然是对象适配器的会更为灵活与广泛。
默认适配器
默认适配器最为简单,封装性稍差,但是最好理解。
默认适配器实际上无法认为是一个真正的适配器,因为他只是对需要实现的接口进行了简易化包装。
他的适配器更像是对于用户来说,复杂的接口实现对用户来说更加友善了,但是对于机器来说效果不大。
这里引用一篇优秀文章的例子进行说明
我们希望使用Appache commons-io包中的 FileAlterationListener对文件进行监控
但是此接口定义了十分多的抽象方法,如果我们直接使用此接口,必须实现他的所有方法,无法避免地会造成代码大量地臃肿。
public interface FileAlterationListener {
void onStart(final FileAlterationObserver observer);
void onDirectoryCreate(final File directory);
void onDirectoryChange(final File directory);
void onDirectoryDelete(final File directory);
void onFileCreate(final File file);
void onFileChange(final File file);
void onFileDelete(final File file);
void onStop(final FileAlterationObserver observer);
}
但是我们往常只希望使用他的创建和删除文件地两个功能,于是我们可以定义如下一个适配器,在这个适配器中,实现了上述地复杂接口,但是所有的方法均置为空方法。当我们需要再使用这个接口的时候,只需要继承这个抽象的适配器对象就可以了,这样就不需要实现所有的方法了。
public class FileAlterationListenerAdaptor implements FileAlterationListener {
public void onStart(final FileAlterationObserver observer) {
}
public void onDirectoryCreate(final File directory) {
}
public void onDirectoryChange(final File directory) {
}
public void onDirectoryDelete(final File directory) {
}
public void onFileCreate(final File file) {
}
public void onFileChange(final File file) {
}
public void onFileDelete(final File file) {
}
public void onStop(final FileAlterationObserver observer) {
}
}
当我们使用的时候,直接继承这个适配器类,选择进行方法地重写。
public class FileMonitor extends FileAlterationListenerAdaptor {
public void onFileCreate(final File file) {
// 文件创建
doSomething();
}
public void onFileDelete(final File file) {
// 文件删除
doSomething();
}
}