设计模式之适配器模式

释放双眼,带上耳机,听听看~!

文章目录

  • 前言

    • 一、适配器模式实现
  • 1、类适配器模式
    * 2、对象适配器模式
    * 3、接口适配器模式

    • 二、适配器模式说明
    • 三、适配器模式总结
  • 1、应用场景
    * 2、优缺点

前言

小六新买了一个小米6手机,它高高兴兴的拿到新手机,想要插上耳机听歌,但发现手机没有耳机孔,仔细查看说明书之后发现,小米6手机是充电孔耳机孔在一起,在插耳机时需要一个耳机转接器,才能插耳机。我们用程序员的眼观来看,这里相当于增加了一个转接器类用于适配耳机,这就类似于我们今天提到的设计模式—适配器模式。

一、适配器模式实现

适配器模式的类图如下所示:
设计模式之适配器模式

其中:

  • Client:客户端,调用自己需要的接口Target
  • Target:定义客户端需要的跟特定需求相关的接口
  • Apaptee:已存在接口,通常满足功能需求但与特定需求接口不一致
  • Adapter:适配器,将Adaptee适配为Client需要的Target接口。

适配器模式的主要功能是进行转换匹配,用来复用已有的功能。适配器模式将某个类的接口转换成客户端期望的另一个接口,目的是消除由于接口不匹配所造成的类的兼容性问题。主要分为三类:类适配器模式、对象适配器模式、接口适配器模式

三种适配器模式有各自的应用场景:

  • 类的适配器模式:将一个类转换成满足另一个新接口的类,创建一个新类,继承原有的类,实现新的接口即可。
  • 对象的适配器模式:将一个对象转换成满足另一个新接口的对象,可以创建一个Wrapper类,持有原类的一个实例,在Wrapper类的方法中,调用实例的方法即可。
  • 接口的适配器模式:当不希望实现一个接口中所有的方法时,可以创建一个抽象类Wrapper,实现所有方法,我们写别的类的时候,继承抽象类即可。

下面针对三种情况进行代码实现:

1、类适配器模式

核心思想就是:有一个Source类,拥有一个方法,待适配,目标接口是Targetable,通过Adapter类,将Source的功能扩展到Targetable里,类图如下所示:
设计模式之适配器模式

代码如下:


1
2
3
4
5
6
7
1public class Source {  
2    public void method1() {  
3        System.out.println("this is original method!");  
4    }  
5}  
6
7

1
2
3
4
5
6
7
8
1public interface Targetable {  
2    /* 与原类中的方法相同 */  
3    public void method1();  
4    /* 新类的方法 */  
5    public void method2();  
6}
7
8

Adapter类继承Source类,实现Targetable接口:


1
2
3
4
5
6
7
8
1public class Adapter extends Source implements Targetable {  
2    @Override  
3    public void method2() {  
4        System.out.println("this is the targetable method!");  
5    }  
6}  
7
8

这样Targetable接口的实现类就具有了Source类的功能。下面为测试类:


1
2
3
4
5
6
7
8
9
1public class AdapterTest {  
2    public static void main(String[] args) {  
3        Targetable target = new Adapter();  
4        target.method1();  
5        target.method2();  
6    }  
7}  
8
9

2、对象适配器模式

基本思路和类的适配器模式相同,只是将Adapter类作修改,这次不继承Source类,而是持有Source类的实例,以达到解决兼容性的问题。如图:
设计模式之适配器模式

只需要修改Adapter类的源码即可:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1public class Wrapper implements Targetable {  
2    private Source source;  
3    public Wrapper(Source source){  
4        super();  
5        this.source = source;  
6    }  
7    @Override  
8    public void method2() {  
9        System.out.println("this is the targetable method!");  
10    }    
11    @Override  
12    public void method1() {  
13        source.method1();  
14    }  
15}
16
17

测试类:


1
2
3
4
5
6
7
8
9
10
1public class AdapterTest {    
2    public static void main(String[] args) {  
3        Source source = new Source();  
4        Targetable target = new Wrapper(source);  
5        target.method1();  
6        target.method2();  
7    }  
8}
9
10

输出与第一种一样,只是适配的方法不同而已。

3、接口适配器模式

接口的适配器模式是当一个接口中有多个抽象方法,但只需要使用其中某些方法,可借助一个抽象类实现该接口的所有的方法,而我们只需写一个类继承该抽象类,重写需要的方法即可。类图如下:
设计模式之适配器模式

示例代码如下:

接口Sourceable:


1
2
3
4
5
6
1 public interface Sourceable {      
2     public void method1();  
3     public void method2();  
4 }
5
6

抽象类Wrapper2:


1
2
3
4
5
6
1public abstract class Wrapper2 implements Sourceable{  
2    public void method1(){}  
3    public void method2(){}  
4}  
5
6

实现类:


1
2
3
4
5
6
7
1public class SourceSub1 extends Wrapper2 {  
2    public void method1(){  
3        System.out.println("the sourceable interface's first Sub1!");  
4    }  
5}
6
7

1
2
3
4
5
6
7
1public class SourceSub2 extends Wrapper2 {  
2    public void method2(){  
3        System.out.println("the sourceable interface's second Sub2!");  
4    }  
5}
6
7

二、适配器模式说明

适配器模式的本质是:转换匹配,复用功能。适配器模式中被适配的接口Adaptee与适配的接口Target没有关系,他们中的方法可以相同,也可以完全不同,适配器模式的实现方式是通过组合对象的方式进行的,将功能委托给被适配的对象进行的。

适配器模式调用的序列图如下所示:
设计模式之适配器模式

适配器模式的实现有以下几种:

  • 常见适配:适配器类会实现接口,在实现过程中调用待适配的类中的方法

  • 智能适配器:在适配器类中实现接口中定义的新方法,通常来说,适配器类中既可以通过借助继承类中的方法实现高层功能,也可以实现接口中定义的新方法,进行功能扩展。

  • 缺省适配:即对接口的缺省实现,即接口适配器模式。

此外,在适配过程中,可能接口功能的实现需要多个待适配类中的方法交互才能满足需求,即同时适配多个类。适配实现的复杂度取决于待适配类与接口的相似度,相似程度越高,适配类的实现难度越低。

在实际项目过程中,通常会存在两个版本共存的情况,这就是需要使用到双向适配器。示例代码如下:

两个版本的实现代码:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
1public interface Targetable1 {
2   public void produce1();
3}
4public class Target1 implements Targetable1 {
5   @Override
6   public void produce1() {
7       System.out.println("Targetable1的produce1实现");
8   }
9}
10
11public interface Targetable2 {
12  public void produce2();
13}
14public class Target2 implements Targetable2 {
15  @Override
16  public void produce2() {
17      System.out.println("Targetable2的produce2实现");
18  }
19}
20
21

适配器类的代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
1public class Adapter implements Targetable1, Targetable2 {
2
3    private Targetable1 target1;
4    private Targetable2 target2;
5
6    @Override
7    public void produce1() {
8        target1.produce1();
9    }
10
11    @Override
12    public void produce2() {
13        target2.produce2();
14    }
15}
16
17

实际上,在使用适配器过程中存在一个问题:被适配的对象不兼容Adapter适配器类,这使得适配器类的适用范围受到限制。而双向适配器则解决了这样的问题,可以满足不同客户采用不同方式查看同一不同对象的需求。

三、适配器模式总结

1、应用场景

  • 实现已实现接口的复用,利用已有的代码实现功能。
  • 使用已存在的部分子类,可选用随想适配器,适配子类的父类。

2、优缺点

优点

  • 更好的复用性。适配器模式可复用已实现接口的兼容。
  • 更好的扩展性。实现适配器的过程中可以调用自己开发的功能,实现系统的扩展。

缺点

过多使用适配器,系统会比较混乱,不易理解

参考:文章主要参考《研磨设计模式》一书

给TA打赏
共{{data.count}}人
人已打赏
安全运维

基于spring boot和mongodb打造一套完整的权限架构(二)【MAVEN依赖以及相应配置】

2021-12-11 11:36:11

安全运维

Ubuntu上NFS的安装配置

2021-12-19 17:36:11

个人中心
购物车
优惠劵
今日签到
有新私信 私信列表
搜索