设计模式-适配器模式

题外话

最近在系统性整理和输出之前的知识点(简言之:准备面试🤡)。整理设计模式这一块,最大的感触是随着阅读代码量的增加和接触的业务场景变多,很多设计模式理解起来不再那么别扭。从项目工程管理的角度来看最直观,优雅?不,“实在是妙啊”

概述

适配器的核心思想是什么,无非就是适配器实现目标接口,同时持有待适配对象的引用,目标方法的具体实现则通过持有的待适配对象来处理。别划走,我来说人话~

众所周知,接口既是规范、协议。你作为老板定义了一套规范(接口),然后工人按照规范做事(接口实现类),一切安好。现在来了个老外(待适配对象),看不懂你的规范,同时你又需要将它纳入到你的体系中,怎么做?找个人(适配器)帮他翻译,但具体的活还得老外自己干。
宇宙惯例,举个插头适配器的例子,这个例子我几年前写过,现在回来再看,之前写的乱七八糟,基于现有的理解又重新写了一版。很多设计模式的学习过程我都有这种感受,可能这就是“常读常新”吧

场景1

中国小伙去美国旅游,手机需要充电

// 1.美国插头工业标准接口
public interface USPlug {
    void getPower();
}
// 2.按照工业标准制作的美国插头
public class USPlugImpl implements USPlug {
    @Override
    public void getPower() {
        System.out.println("getting power success");
    }
}
// 3.美国的插座
public class USSocket {
    // 只能插入美国标准的插头(合情合理~)
    public void plugin(USPlug usPlug) {
        usPlug.getPower();
    }
}
// 4.中国小伙的插头(CNPlug 是中国插头的工业标准)
public class CNPlugImpl implements CNPlug {
    @Override
    public void tongDian() {
        System.out.println("插头通电了");// 中国插头说中文,合情合理
    }
}

工业标准不同,中美插头样式也不一样,美国插座只能插入美国行业标准(USPlug接口)的插头,中国小伙手机没电已成定局…
适配器模式救场:

// 5.适配器实现了美国插头的接口规范,必然可以使用美国插座
public class PlugAdapter implements USPlug {
    @Resource
    private CNPlug cnPlug;
    public PlugAdapter() {}
    public PlugAdapter(CNPlug cnPlug) {// 通过构造函数持有待适配的对象
        this.cnPlug = cnPlug;
    }
    @Override
    public void getPower() {
        cnPlug.tongDian();// 给国产插头通电(接口的方法交由待适配的对象完成)
    }
}
// 6.测试
@SpringBootTest
public class AdapterDemo1Test {
    @Resource
    USPlug usPlug;
    @Resource
    USSocket usSocket;
    @Resource
    USPlug plugAdapter;
    @Test
    public void test() {
        usSocket.plugin(usPlug);// 美国插头
        usSocket.plugin(plugAdapter);//适配器插头
    }
}
// 7.输出
getting power success
插头通电了

场景2

如果你经常接触第三方SDK的接入,或者新系统接入老系统功能,你很快就能体会适配器模式、门面模式的含义,至于模式的精髓、精通? 曾经我也…最近“常读常新”的感受让我无地自容🫣

// 做过保险相关的SaaS服务,其中有一块功能是做数据清洗,
// 大体就是把各大保司格式不同的保全数据处理成统一格式的对象

// 1.定义清晰接口
public interface IDataCleaning {
    String cleaning(IMaintenanceInfo maintenanceInfo);
}
// 2.如果我们自己能控制数据,那太简单了
// 传入对象,进行处理(话说如果能决定传入的对象,也就没有数据清洗这个需求了)
public class IDataCleaningImpl implements IDataCleaning {
    @Override
    public String cleaning(IMaintenanceInfo maintenanceInfo) {
        maintenanceInfo.getMaintenanceInfo();
        return "success";
    }
}
// 3.对接的各大保司提供的SDK都有获取保全的方法,但格式肯定是不统一的,比如A公司:
public class PARSSdk {
    public String printMainInfo() {
        System.out.println("平安人寿 保全信息");
        return null;
    }
}
// B公司:
public class PiccSdk {
    public String getDataInfo() {
        System.out.println("PICC 获取保全信息");
        return null;
    }
}

// 4.别人的SDK我们改不了,那我们就进行适配:适配器实现我们的IDataCleaning接口

// A公司获取保全数据的适配器
public class PARSAdapter implements IMaintenanceInfo {
    private PARSSdk parsSdk;
    public PARSAdapter() {}

    public PARSAdapter(PARSSdk parsSdk) {
        this.parsSdk = parsSdk;
    }
    @Override
    public String getMaintenanceInfo() {
        parsSdk.printMainInfo();
        return null;
    }
}
// B公司获取保全的适配器
public class PiccAdapter implements IMaintenanceInfo {
    private PiccSdk piccSdk;
    public PiccAdapter() {}
    public PiccAdapter(PiccSdk piccSdk) {
        this.piccSdk = piccSdk;
    }
    @Override
    public String getMaintenanceInfo() {
        piccSdk.getDataInfo();
        return null;
    }
}
// 5.测试和运行结果
@SpringBootTest
public class AdapterDemo2Test {
    @Resource
    private IDataCleaning dataCleaning;
    @Resource
    private IMaintenanceInfo maintenanceInfo;
    @Resource
    private PiccAdapter piccAdapter;
    @Resource
    private PARSAdapter parsAdapter;
    @Test
    public void test() {
        dataCleaning.cleaning(maintenanceInfo);// 测试类
        dataCleaning.cleaning(parsAdapter);// A公司适配
        dataCleaning.cleaning(piccAdapter);// B公司适配
    }
}
// 打印
获取保全信息成功
PICC 获取保全信息
平安人寿 保全信息

其他保司的接入直接增加相应的适配器,符合开闭原则。
看到这里,再去思考,如果让你定义一套日志接口的规范,其他日志框架该如何遵循你的规范呢?
定义了Logger接口,编写log4j12适配器、jdk14适配器,哎~这就是SLF4J(Simple Logging Facade for Java)。看到facade了没,下回聊一下门面模式🥱

思考

有没有觉得适配器模式中的一些操作和另一个设计模式很像,对,代理模式。
代理模式:代理对象通过实现与被代理对象相同的接口,并持有被代理对象的引用,“真正做事”的是被代理对象。
适配器模式:适配器通过实现目标接口,并持有待适配对象的引用,“真正做事”的是待适配对象。
反正最初我是感觉两者的“作案”手法一致。区分它们,个人感觉需要从两个模式的目的和关注点去考虑:
目的:适配器是为了使接口兼容;代理则是控制被代理者的访问(使用者感知不到被代理者的存在)
关注点:适配器关注的是不同规范下的接口兼容和适配;代理模式则关注对被代理者添加额外的操作逻辑

  • 10
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值