Java23中设计模式适配器的实战场景,修改旧依赖包中的方法,实现功能
场景设定:
我们引入外部jar依赖包 old-third-sdk.jar,包里的源码我们无法修改、只能调用。
依赖包里的类不止一个支付方法,还有一大堆配套业务方法;
我们用继承适配器实现新旧接口适配,同时演示:重写父类需要改变的方法,且剩余的方法会不会被影响?需要在重写或者调用?
一、依赖包内部原有类(只读,无法修改)
// 位于第三方依赖包 old-third-sdk.jar
public class OldPaySdk {
// 方法1:老旧支付核心方法(需要适配改造)
public void sendOldPay(String orderNo, Integer money) {
System.out.println("【依赖包原生】发起老式支付:订单:" + orderNo + ",金额:" + money);
}
// 方法2:查询余额(不需要改动,直接沿用)
public Integer getBalance(String accountId) {
System.out.println("【依赖包原生】查询账户余额");
return 10000;
}
// 方法3:关闭支付通道(工具方法,原样保留)
public void closeChannel() {
System.out.println("【依赖包原生】关闭支付通道");
}
// 更多其他附属方法...
}
二、项目自定义新标准接口
// 我们项目统一支付规范
public interface NewPayApi {
void pay(String orderId, Integer amount);
}
三、继承适配器:继承依赖类 + 实现新接口 + 重写父类方法
/**
* 适配器:extends 依赖包里的OldPaySdk
* 1. 自动继承依赖包所有public方法:sendOldPay、getBalance、closeChannel 全部拿到
* 2. 重写父类sendOldPay,修改原有逻辑
* 3. 实现新项目接口完成适配
*/
public class PayAdapter extends OldPaySdk implements NewPayApi {
// ========== 1、重写依赖包原生支付方法 ==========
@Override
public void sendOldPay(String orderNo, Integer money) {
System.out.println("【适配器重写】前置校验参数、统一日志、异常捕获");
// 可选:可以调用父类原版逻辑 super.sendOldPay(...)
super.sendOldPay(orderNo, money);
System.out.println("【适配器重写】支付完成后置处理");
}
// ========== 2、实现新项目标准接口 ==========
@Override
public void pay(String orderId, Integer amount) {
// 内部调用自己重写后的支付方法
sendOldPay(orderId, amount);
}
}
注意:这里只重写父类我们需要调用的方法,剩余的方法完全不受影响,还是继续从旧的依赖包中进行调用
四、客户端调用测试,直观区分效果
public class Client {
public static void main(String[] args) {
PayAdapter adapter = new PayAdapter();
System.out.println("=====1.调用适配后的新接口(业务主流调用)=====");
adapter.pay("ORD001", 299);
System.out.println("\n=====2.直接调用被重写的依赖包原有方法=====");
adapter.sendOldPay("ORD002", 599);
System.out.println("\n=====3.调用依赖包里其余未重写的普通方法=====");
Integer balance = adapter.getBalance("ACC123");
System.out.println("余额:" + balance);
adapter.closeChannel();
}
}
运行结果
=====1.调用适配后的新接口(业务主流调用)=====
【适配器重写】前置校验参数、统一日志、异常捕获
【依赖包原生】发起老式支付:订单:ORD001,金额:299
【适配器重写】支付完成后置处理
=====2.直接调用被重写的依赖包原有方法=====
【适配器重写】前置校验参数、统一日志、异常捕获
【依赖包原生】发起老式支付:订单:ORD002,金额:599
【适配器重写】支付完成后置处理
=====3.调用依赖包里其余未重写的普通方法=====
【依赖包原生】查询账户余额
余额:10000
【依赖包原生】关闭支付通道
五、核心结论:依赖包里剩下的其他方法受不受影响?
-
被你重写的方法
父类原本逻辑被覆盖,无论通过新接口调用、还是直接调用原方法名,执行的都是适配器重写后的代码;
想要调用依赖包原版逻辑,只能在适配器内部写super.方法名()。 -
依赖包里其余没有重写的所有方法(getBalance、closeChannel)
✅ 完全不受任何影响
在Java中,适配器通过继承实现,调用时依旧执行依赖jar内部原本的源码,不会被修改、不会被包装。 -
边界补充
- 依赖包里
private私有方法:继承拿不到,完全无关; final方法:无法重写,只能原样调用;- 静态方法:不存在重写,只会隐藏,一般不会拿来做适配。
六、继承方式在这里的隐患(对接第三方jar弊端)
- 单继承限制:只能继承这一个支付SDK,无法同时对接微信、支付宝多个第三方依赖;
- 耦合极强:依赖包升级改动任意方法,适配器极易报错;
- 如果你不需要用到父类大部分工具方法,继承会白白继承一堆冗余代码。
七、对比主流组合写法(无继承)
适配器只持有依赖对象,不会继承全部方法,不会污染空间,其余方法按需调用,更加稳妥:
public class PayAdapter implements NewPayApi {
// 持有依赖对象,而非继承
private OldPaySdk sdk = new OldPaySdk();
@Override
public void pay(String orderId, Integer amount) {
sdk.sendOldPay(orderId, amount);
}
}
注意:这里介绍是根据上述中例子的使用方式,简化的一种。因为上述中描述的业务比较复杂,不太适合用适配器模式。一般适配器模式是放在变化较小的场景中使用最合适。