发布于 

Java设计模式之——适配器模式

5.1 适配器模式简介

  • 适配器模式(Adapter Pattern

    • ⻅名知意,是作为两个不兼容的接⼝之间的桥梁,属于结构型模式
    • 适配器模式使得原本由于接⼝不兼容⽽不能⼀起⼯作的那些类可以⼀起⼯作
    • 常⻅的⼏类适配器
      • 类的适配器模式
        • 将⼀个类转换成满⾜另⼀个新接⼝的类时,可以使⽤类的适配器模式,创建⼀个新类,继承原 有的类,实现新的接⼝即可
      • 对象的适配器模式
        • 将⼀个对象转换成满⾜另⼀个新接⼝的对象时,可以创建⼀个适配器类,持有原类的⼀个实例,在适配器类的⽅法中,调⽤实例的⽅法就⾏
      • 接⼝的适配器模式
        • 不想实现⼀个接⼝中所有的⽅法时,可以创建⼀ 个Adapter,实现所有⽅法,在写别的类的时 候,继承Adapter类即可
  • 应⽤场景

    • 电脑需要读取内存卡的数据,读卡器就是适配器

    • ⽇常使⽤的转换头,如电源转换头,电压转换头

    • 系统需要使⽤现有的类,⽽这些类的接⼝不符合系统的 需要

    • JDK中InputStreamReader就是适配器

    • JDBC就是我们⽤的最多的适配器模式

      1
      2
      3
      JDBC给出⼀个客户端通⽤的抽象接⼝,每⼀个具体数据库⼚商 
      如 SQL Server、Oracle、MySQL等,就会开发JDBC驱动,
      就是⼀个介于JDBC接⼝和数据库引擎接⼝之间的适配器软件

5.2 接⼝的适配器案例

  • 设计模式的疑惑

    • 会感觉到好像是理解了模式的功能,但是⼀到真实的系统开发中,就不知道如何使⽤这个模式了
    • 前⾯每个案例都有讲实际的编码操作,⼤家⼀定要充分领悟
  • 接⼝适配器

    1
    2
    有些接⼝中有多个抽象⽅法,当我们写该接⼝的实现类时,必须实现该接⼝的所有⽅法,
    这明显有时⽐较浪费,因为并不是所有的⽅法都是我们需要的,有时只需要实现部分接⼝就可以了
  • 编码实战:

首先我们来定义一个支付网关接口PayGateWay(仅仅是模拟)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* @Auther: csp1999
* @Date: 2020/11/09/18:40
* @Description: 支付网关接口
*/
public interface PayGateWay {
/**
* 下单
*/
void unifiedOrder();
/**
* 退款
*/
void refund();
/**
* 查询支付状态
*/
void query();
/**
* 发红包
*/
void sendRedPack();
}

再来一个视频产品订单类ProductVideoOrder 去实现 PayGateWay 接口:

1
2
3
4
5
6
7
/**
* @Auther: csp1999
* @Date: 2020/11/09/18:44
* @Description: 视频产品订单
*/
public class ProductVideoOrder implements PayGateWay{
}

当我们实现该接口的时候,默认就需要实现接口中的所有抽象方法。而实际上如果我们只需要在ProductVideoOrder

实现下单unifiedOrder()refund() 退款功能,而并不需要多余的查询支付状态 query(); 和 发红包sendRedPack();功能,那么如何解决呢?

这就需要用到一个适配器,适配器去实现PayGateWay 接口的所有方法,ProductVideoOrder 只需要继承 该适配器,就可以按需重写相关方法即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @Auther: csp1999
* @Date: 2020/11/09/18:45
* @Description: 支付网关接口的适配器
*/
public class PayGateWayAdapter implements PayGateWay{
@Override
public void unifiedOrder() {
}
@Override
public void refund() {
}
@Override
public void query() {
}
@Override
public void sendRedPack() {
}
}

然后在ProductVideoOrderProductVipOrder 按需重写响应的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
/**
* @Auther: csp1999
* @Date: 2020/11/09/18:48
* @Description: 超级会员用户产品订单
*/
public class ProductVipOrder extends PayGateWayAdapter{
@Override
public void unifiedOrder() {
super.unifiedOrder();
}
@Override
public void refund() {
super.refund();
}
@Override
public void sendRedPack() {
super.sendRedPack();
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* @Auther: csp1999
* @Date: 2020/11/09/18:44
* @Description: 视频产品订单
*/
public class ProductVideoOrder extends PayGateWayAdapter{
@Override
public void unifiedOrder() {
System.out.println("产品下单...");
}
@Override
public void refund() {
System.out.println("产品退款...");
}
}

5.3 类的适配器实战

  • 类的适配器模式
    • 将⼀个类转换成满⾜另⼀个新接⼝的类时,可以使⽤ 类的适配器模式,创建⼀个新类,继承原有的类,实现 新的接⼝即可

首先,假设我们在升级或者优化一个项目时,需要将老的模块中的相关功能进行升级扩展,这个功能目前是由模块中的某个类OldModule进行实现。

1
2
3
4
5
6
7
8
9
10
/**
* @Auther: csp1999
* @Date: 2020/11/09/19:35
* @Description:
*/
public class OldModule {
public void methodA(){
System.out.println("OldModule 中的 methodA...");
}
}

那么我们如何在不改动老模块中OldModule类的前提下,对其所负责的业务功能进行扩展升级呢?

接下来,我们先将要扩展升级的相关功能方法,包括现有功能的方法在目标接口TargetModule中进行定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/**
* @Auther: csp1999
* @Date: 2020/11/09/19:36
* @Description:
*/
public interface TargetModule {
/**
* 和需要适配的类的方法名一样
*/
public void methodA();
/**
* 新的方法,如果有多个新的方法直接编写即可
*/
public void methodB();
public void methodC();
}

然后通过类的适配器,进行适配OldModuleTargetModule,这样就可以做到将⼀个类转换成满⾜另⼀个新接⼝的类,且不改动原有类~

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* @Auther: csp1999
* @Date: 2020/11/09/19:37
* @Description: 类的适配器
*/
public class Adapter extends OldModule implements TargetModule{
/**
* 注意: 已经在OldModule中实现的 methodA()是不用再实现的
*/
/**
* 新的方法B
*/
@Override
public void methodB() {
System.out.println("Adapter 中的 methodB...");
}
/**
* 新的方法C
*/
@Override
public void methodC() {
System.out.println("Adapter 中的 methodC...");
}
}

测试一下效果:

1
2
3
4
5
6
7
@Test
public void testClassAdapater(){
TargetModule targetModule = new Adapter();
targetModule.methodA();
targetModule.methodB();
targetModule.methodC();
}

输出结果为:

1
2
3
OldModule 中的 methodA...
Adapter 中的 methodB...
Adapter 中的 methodC...

这样就做到了 在不改动原来OldModule 类以及其中相关功能方法的前提下,对其进行扩展实现TargetModule 接口中新增加的业务功能!

原文:https://www.kuangstudy.com/bbs/1374938278314143745