Java设计模式之适配器模式

适配器模式理解起来很简单,就是字面意思,大家生活中很常见的比如,usb转type-c 转接头、usb转HDMI 转接头等等,通过这个工具可以把所有usb插口设备与HDMI插口的设备链接起来使用。在java中适配器模式的作用跟这个例子是一样的,下面我用220v交流电转成我们手机接受的5v直流电为例 转换成代码给大家讲解。

今天早上在家里拍了三张照片,和本文是有关系的哦,为了方便大家理解。

落实到实际业务中,可以假设现在有一方法或工具已经写好了,但是和你们实际业务需要的参数或返回类型等不匹配,这时我们需要一个中间者,帮你转换一下,这就是适配器。

介绍一下适配器中三个角色

Source:需要被适配的类、接口、对象,如220v交流电。 
Destination:需要得到的类,Source通过适配得到的类对象,也就是我们期待得到的接口,如一个可以输出5v的接口。 
Adapter:适配器类,协调Source和Destination,使两者能够协同工作,如这个工具。

介绍一下Java中的适配器种类

我理解的适配器是三种,大家在网上看的资料一般都是两种,那是他把接口适配器和对象适配器归位一类了,其实接口适配器更强大,我们在下面代码中就可以看出来。

类适配器模式

类适配器使用对象继承然后实现需要转换接口的方式,缺点就是扩展性差,在适配器类中直接操作被适配类的方法。

下面我用代码给大家讲解,需要注意的是,我讲解三种方式的适配器中唯一一个不变的类就是被适配的类,如下:

public class AC220V {
   //需要适配的对象 ,Source角色
   public int output220V() {
       int output = 220;
       return output;
   }
}

我们上面的小灯需要一个5v的直流电,这个角色在代码中是以接口的形式存在的,如下。

public interface DC5V {
   //通过适配器得到的类,Destination角色
   int output5V();
}

最后我们只需要适配器把220v和5v的接口结合一下就可以了。

public class PowerAdapter extends AC220V implements DC5V {
   //适配器Adapter
   public int output5V() {
       int out = super.output220V();
       return out / 44;
   }
}

这是测试类,输出是5,我就不再这里贴图了,感兴趣在下面加微信给你发demo。

public class ClassAdapterTest {
   //测试
   public static void main(String[] args) {
       DC5V dc5v = new PowerAdapter();
       int a = dc5v.output5V();
       System.out.println(a);
   }
}

对象适配器

对象适配器在类适配器的基础上只对适配器类进行了改造,让我们来看一下被改造的适配器是什么样的。

我们之前的DV5V.java 和AC200V.java不变。

我们没有继承被适配的类,我们的适配器想要使用他就要通过构造方法调用,所以代码改造如下,把被适配的类看作对象注入到适配器里,故此方法叫做对象适配器,这样理解会好一点。

public class PowerAdapter implements DC5V {
   private AC220V ac220V;

   public PowerAdapter(AC220V ac220V) {
       this.ac220V = ac220V;
   }

   @Override
   public int output5V() {
       int output = 0;
       if (ac220V != null) {
           output = ac220V.output220V() / 44;
       }
       return output;
   }
}

接口适配器

前面我们提到接口适配器的优势在于扩展性高,所以如果当前业务今后需要扩展或者现在需要适配出来的接口有很多,比如上面我只能输出5v直流电,那么我想让适配器还可以输出10v、20v甚至更多的场景时,用接口适配器最合适不过了。

适配的根本在于被适配的类,跟上面的一样还是AC220V,参照上面就可以。

下面我要把我理想中输出的电压的接口写出来,不仅可以输出5v,还可以输出10v,如下

public interface DCOutput {
   int output5V();

   int output10V();
}

这回让我们看看适配器的变化,和对象适配器一样,需要把被适配对象注入进来,通过构造方法调用。同样实现了需要被适配出来的电压接口,这回重写了两个方法而已 。现在我的适配器只是让220v电压接通到我的 5v和 10v的转接口上了,但是变压的操作并不在这里做,接着往下看。

public class PowerAdapter implements DCOutput {
   public AC220V ac220V;

   public PowerAdapter(AC220V ac220V) {
       this.ac220V = ac220V;
   }

   @Override
   public int output5V() {
       return ac220V.output220V();
   }

   @Override
   public int output10V() {
       return ac220V.output220V();
   }
}

我们独立出来两个类,分别去把 220v转成相应的电压输出出来,

public class Adapter5V extends PowerAdapter {
   public Adapter5V(AC220V ac220v) {
       super(ac220v);
   }
   public int output5V() {
       int output = 0;
       if (ac220V != null) {
           output = ac220V.output220V() / 44;
       }
       return output;
   }
}


public class Adapter10V extends PowerAdapter {
   public Adapter10V(AC220V ac220V) {
       super(ac220V);
   }

   public int output10V() {
       int output = 0;
       if (ac220V != null) {
           output = ac220V.output220V() / 22;
       }
       return output;
   }
}

大家可以把接口适配器理解成一拖三转接头。

本文演示的demo如下

总结

被适配类(Source)的存在形式决定了适配器的名字。类适配器就是继承Source类,对象适配器就是持有Source类对象,接口适配器是基于对象适配器的改进。如果有90%的把握确定需要适配出来的接口只有一种或两种不建议用这个方法了,建议使用对象适配器,如果将来需要适配出来的接口更多,那么用接口适配器,没有什么一定和必须,选择合适的就好了。

作者:

喜欢围棋和编程。

 
发布于 分类 编程标签

发表评论

电子邮件地址不会被公开。