Adapter模式


title: Adapter模式
tag: 笔记 设计模式

image-20231018141003528

Adapter模式

在程序世界中,经常会存在现有的程序无法直接使用,需要做适当的变换之后才能使用的情况。这种用于填补“现有的程序”和“所需的程序”之间差异的设计模式就是Adapter模式。
Adapter模式也被称为Wrapper模式。Wrapper有“包装器”的意思,就像用精美的包装纸将普通商品包装成礼物那样,替我们把某样东西包起来,使其能够用于其他用途的东西就被称为“包装器”或是“适配器”。

Adapter模式有下面两种模式:

  • 类适配器模式(继承实现)
  • 对象适配器模式(委托实现)

下面是一个简单的示例。

使用继承的适配器

这个示例程序是一个会将输入的字符串显示为 (hello)或者*hello*的简单程序:

  • Banner类:有两个方法对字符串做不同的处理。
    • showWithParen:将字符串用()括起来。
    • showWithAster:将字符串用**包起来。
  • Print接口:定义了两个抽象方法用不同的方式输出。
    • printWeak:弱化字符串显示(括号)
    • printStrong:强化字符串显示(星号)

现在我们要实现的就是使用Banner类编写一个实现Print接口的类。Banner就类似我们现有的程序,而Print接口就是我们的需求,现在我们需要在它们之前编写一个适配器(adapter)PrintBanner来实现目标需求。

UML图如下:

image-20231018160854436

Banner类

现有程序:

public class Banner {
    private String s;

    public Banner(String s){
        this.s = s;
    }

    public void showWithParen(){
        System.out.println(new StringBuilder().append("(").append(s).append(")").toString());;
    }

    public void showWithAster(){
        System.out.println(new StringBuilder().append("*").append(s).append("*").toString());;
    }
}

Print接口

我们要实现的需求

public interface Print {
    void printWeak();
    void printStrong();
}

PrintBanner类

该类扮演适配器的角色,它继承了Banner又实现了Print接口。

public class PrintBanner extends Banner implements Print{
    public PrintBanner(String s) {
        super(s);
    }
    @Override
    public void printWeak() {
        showWithParen();
    }

    @Override
    public void printStrong() {
        showWithAster();
    }
}

测试

public static void main(String[] args) {
    Print print = new PrintBanner("Hello World");
    print.printWeak();
    print.printStrong();
}

输出:

(Hello World!)
*Hello World!*

这里使用Print类型(接口)来表示PrintBanner示例(实现)的目的是明确表示程序的意图PrintBanner类仅仅只使用Print接口中的方法。因为在有些情况,适配器(PrintBanner)中的方法会比需求接口(Print)中的方法多。

使用委托的适配器

在上面的示例中,我们将适配器(PrintBanner)继承了适配者(Banner),在很多情况我们都可以使用委托代替继承的方法来将继承关系(is)更改为聚合关系(has)

我们在PrintBanner中添加Banner实例的成员变量,并在其构造方法中执行初始化。然后我们通过Banner来调用它的方法,这样就实现了与继承相同的作用。

UML图:

image-20231018165003984

修改为使用委托的适配器我们只需要修改适配器(PrintBanner)即可。

PrintBanner类

使用委托代替继承的方法,我们只需要实现Print接口即可:

public class PrintBanner implements Print{
    Banner banner;

    public PrintBanner(String s) {
        banner = new Banner(s);
    }

    @Override
    public void printWeak() {
        banner.showWithParen();
    }

    @Override
    public void printStrong() {
        banner.showWithAster();
    }
}

测试

public static void main(String[] args) {
    Print print = new PrintBanner("Hello World!");
    print.printWeak();
    print.printStrong();
}

输出:

(Hello World!)
*Hello World!*

与之前相同。

Adapter模式中登场的角色

在Adapter模式中下面几种角色:

  • Target(对象)该角色负责定义所需的方法。在示例程序中,由Print接口扮演此角色。
  • Client(请求者)该角色负责使用Target角色所定义的方法进行具体处理。在实例程序中由测试程序扮演该角色。
  • Adaptee(被适配)该角色是一个持有既定方法的角色。在示例程序中,由Banner类扮演此角色。
  • Adapter(适配器)Adapter模式的主人公。使用Adaptee角色的方法来满足Target角色的需求,这是Adapter模式
    的目的,也是Adapter角色的作用。在实例程序中,由PrintBanner扮演此角色。

类适配器的类图

image-20231018203927976

对象适配器的类图

image-20231018204111676

拓展思路

什么时候使用Adapter模式

如果一个方法是我们需要的方法,我们为何不直接在当前类实现而是要使用Adapter模式呢?

很多时候,我们并非从零开始编程,经常会用到现有的类。特别是当现有的类已经被充分测试过了,Bug很少,而且已经被用于其他软件之中时,我们更愿意将这些类作为组件重复利用

Adapter模式会对现有的类进行适配,生成新的类。通过该模式可以很方便地创建我们需要的方法群。当出现Bug时,由于我们很明确地知道Bug不在现有的类(Adaptee角色)中,所以只需调查扮演Adapter角色的类即可。这样一来,代码问题的排查就会变得非常简单。

扩展而不是修改

当我们想让现有的类适配新的接口时,我们常常会有修改原有的类来适配接口的想法,这样修改类可能会导致一些问题。

使用Adapter模式可以在完全不改变现有代码的前提下使现有代码适配于新的接口。

版本升级和兼容性

软件的生命周期总是伴随着版本的升级,在版本升级的时候就会伴随着版本兼容问题,很多时候我们都不能完全抛弃旧版本。这个时候我们就可以使用Adapter模式来同时维护旧版本和新版本。

我们可以让新版本扮演adaptee模式而旧版本扮演Target角色,然后编写一个扮演Adapter的类,让它使用新版本的类来实现旧版本的方法:

image-20231018212821394

相关的设计模式

  • Bridge模式

Adapter模式用于连接接口(API)不同的类,而Bridge模式则用于连接类的功能层次结构与实现层次结构

  • Decorator模式

Adapter模式用于填补不同接口(API)之间的缝隙,而Decorator模式则是在不改变接口(API)的前提下增加功能
t=“image-20231018212821394” style=“zoom:80%;” />

相关的设计模式

  • Bridge模式

Adapter模式用于连接接口(API)不同的类,而Bridge模式则用于连接类的功能层次结构与实现层次结构

  • Decorator模式

Adapter模式用于填补不同接口(API)之间的缝隙,而Decorator模式则是在不改变接口(API)的前提下增加功能

  • 20
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值