适配器模式来啦

news/2024/12/24 16:29:42

网上的大多数的资料中适配器模式和代理模式都是紧挨着进行介绍的,为什么呢???

是因为适配器模式和代理模式有太多的相似之处,可以进行联动记忆但是也要做好区分。

在菜鸟教程中,适配器模式的定义是作为两个不兼容接口之间的桥梁使其变得可兼容;从代码层面来解释就是有一个接口需要实现,但是现有的对象都不满足,需要对对象进行适配(就是加一层伪装)

适配器模式总共有三种,默认适配器模式,对象适配器模式,类适配器模式

一、默认适配器模式

用 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();
    }
}

默认适配器模式是三种适配器中最简单的一种模式,整体是为了单一职责原则,过滤掉本身不需要的能力,防止给调用方造成空能力的假象

二、对象适配器模式

大家都看过电影聊斋画皮吧,其中九霄美狐小唯因王家军首领王生勇猛英俊对其萌生爱意,想取代王生妻子佩蓉的地位。但是小唯是狐狸啊,想要和王生在一起至少得变成一个人吧(至少看起来是人),所以小唯披上了一个绝色美女的皮用于迷惑王生,使得狐狸小唯的行为在王生等人看来和自己没什么区别。

举个🌰

public interface Fox {
    public void walk(); // 走路
      public void eat(); // 吃饭
}

public interface Person {
    public void walk(); // 走路
      public void eat(); // 吃饭
}

public class XiaoWei implements Fox {
    public void walk() {
        System.out.println("狐狸走路,四条腿");
    }
      public void eat() {
        System.out.println("狐狸吃饭");
    }
}

public class WangSheng implements Person {
    public void walk() {
        System.out.println("人走路,两条腿");
    }
      public void eat() {
        System.out.println("人吃饭");
    }
}

人接口有 walk() 和 eat() 两个方法,狐狸 Fox 如果要冒充人, walk() 和 eat() 两个方法是现成的,但是本质上是不同的(狐狸实现Fox接口 , 人实现Person接口),所以需要适配让狐狸小唯看起来像人

这里相当于祭炼法器了(FoxAdapter)

// 毫无疑问,首先,这个适配器肯定需要 implements Person,这样才能当做人来看
public class FoxAdapter implements Person {

    Fox fox;
    // 构造方法中需要一个狐狸的实例,此类就是将这只狐狸适配成人来用
      public FoxAdapter(Fox fox) {
        this.fox = fox;
    }

    // 实现人的走路方法
      @Override
      public void walk() {
        // 内部其实是一只狐狸的走路
        fox.walk();
    }

      @Override
      public void eat() {
        // 内部其实是一只狐狸的吃饭    
        fox.eat();
    }
}

然后就是使用法器(FoxAdapter)

public static void main(String[] args) {
    // 有一只美狐小唯
      Fox xiaowei = new XiaoWei();
      // 成功将美狐小唯适配成人
      Person person = new FoxAdapter(xiaowei);
      ...
}

用一个小小的图来加深一下理解

adapter-1

三、类适配器模式

小心,看图😏

adapter-1

 看到这个图,大家应该很容易理解的吧,通过继承的方法,适配器自动获得了所需要的大部分方法,在适配器中包装一下不就妥妥的。这个时候,客户端使用更加简单,直接 Target t = new SomeAdapter(); 就可以了

四、适用场景

适配器模式主要用于查缺补漏阶段而不是设计阶段。当出现两个接口不兼容的问题才会使用该设计模式,而不是一开始就设计成这样的模式。

如果想要对多类对象和对象的能力进行组合叠加可使用桥接模式

五、总结

文章中一开始就说过代理模式和适配器模式是有相似的,get到了吗🤔

代理模式和适配器模式(对象)都是以对象组合的方式进行代理和适配,不过不同的是代理相当于游戏中给游戏角色上外挂,只是对原有能力的增强。例如刺激战场的自动瞄准挂,原本角色就能开枪干人只是中不中的问题,加了外挂增强开枪干人的命中率并没有改变本质行为。适配模式则是本质上的改变,别人是开枪干人,结果你适配成开战斗机扫射。

立秋 渐寒 添衣 勿病 安好

五、引用

1、Java 设计模式 - 掘金

2、适配器模式 | 菜鸟教程


http://www.niftyadmin.cn/n/4924362.html

相关文章

【构造】CF1798 D

Problem - D - Codeforces 题意&#xff1a; 思路&#xff1a; 首先如果 a 全是 00&#xff0c;那么显然无解。 否则考虑从左到右构造新数列&#xff0c;维护新数列的前缀和 s。 如果 s≥0&#xff0c;则在剩余未加入的数中随便选择一个非正数添加到新数列末尾。如果 s<…

Linux root用户执行修改密码命令,提示 Permission denied

问题 linux系统中&#xff08;ubuntu20&#xff09;&#xff0c;root用户下执行passwd命令&#xff0c;提示 passwd: Permission denied &#xff0c;如下图&#xff1a; 排查 1.执行 ll /usr/bin/passwd &#xff0c;查看文件权限是否正确&#xff0c;正常情况是 -rwsr-xr…

linux 内存 - KO内存占用

说明 KO(kernel module)占用的内存分为两部分&#xff1a; 静态占用 &#xff1a;ko insmod时系统固定分配的内存。动态申请 &#xff1a;代码中动态申请的内存&#xff0c;由于申请方式不同&#xff0c;统计的方式也可能不同&#xff0c;例如&#xff1a;使用vmalloc和kmall…

Netty:查看ByteBuf的实现类

io.netty.buffer.ByteBuf是一个抽象类&#xff0c;我们看看它最终的实现类。实现类有多个&#xff0c;具体用的是哪个实现类&#xff0c;跟分配ByteBuf的方式有关。 作为举例&#xff0c;分别用Unpooled和ByteBufAllocator.DEFAUL来分配一个ByteBuf。 package com.thb;import …

jQuery知识

DOM知识 alert(我是弹窗); prompt(弹窗输入);Dom元素节点获取 方式一&#xff1a;通过 id 获取 一个 元素节点&#xff08;为什么是一个呢&#xff1f;因为 id 是唯一的&#xff09; var div1 document.getElementById("box1"); 方式二&#xff1a;通过 标签名 获…

什么是行级锁和表级锁

行级锁和表级锁是数据库中常见的两种锁机制&#xff0c;用于在多个事务并发访问数据库时控制数据的访问权限和并发操作。 行级锁&#xff08;Row-Level Locking&#xff09;&#xff1a; 行级锁是指在数据库表中对每一行数据进行锁定&#xff0c;只有被锁定的行才不能被其他事…

Vue中的的通信方式有几种?隔代组件的通信你用那种方式解决?

props/$emit 适用父子组件通信 ref与parent/children适用父子组件通信 attrs/listeners,provide/inject 适用于隔代组件通信 vuex,EventBus(事件总线) 适用于父子、隔代、兄弟组件通信 slot插槽方式 attrs实例 父组件&#xff08;这时候我们传了两个参数title和type&…

YOLOv5源码中的参数超详细解析(2)— 配置文件yolov5s.yaml

前言&#xff1a;Hello大家好&#xff0c;我是小哥谈。YOLOv5配置了5种不同大小的网络模型&#xff0c;分别是YOLOv5n、YOLOv5s、YOLOv5m、YOLOv5l、YOLOv5x&#xff0c;其中YOLOv5n是网络深度和宽度最小但检测速度最快的模型&#xff0c;其他4种模型都是在YOLOv5n的基础上不断…