真正零修改是将变化点封装为多态:定义接口(如Payment)、各实现类独立扩展、运行时动态注入(如Map<String, Payment>)、default方法统一增强、测试仅依赖接口可轻松Mock。

关键不是“让代码不改”,而是“把变化点关进多态的笼子”——新增业务逻辑只加类、不碰已有调用链,这才是真正零修改。
接口定义行为契约,不写任何 if-else
所有可变场景(如支付方式、通知渠道、校验规则)必须先抽成接口,而不是在方法里堆条件分支。
- 定义 Payment 接口,只声明
pay(BigDecimal amount) - 支付宝、微信、PayPal 各自实现该接口,互不干扰
- 订单服务里只持有
private Payment payment;,调用payment.pay(...)即可 - 后续加数字货币支付?只需新增一个
CryptoPayment类,其他代码一行不动
运行时动态选择,别在代码里 new 或判断类型
硬编码 if (channel.equals("wechat")) { new WeChatPay(); } 是多态的假象,实际每次新增都要改这里,OCP 立刻失效。
- 用 Spring 的
@Autowired List<Payment>或Map<String, Payment>自动收集所有实现 - 根据配置或参数(如
order.getChannel())从 Map 中取对应实例 - 封装成策略上下文,对外提供
PaymentStrategy.get(String channel).pay(...) - 这样新增渠道,只加类 + 加个
@Service("alipay")注解,主流程完全隔离
default 方法用于通用能力升级,不破坏现有实现
想给所有支付方式加统一日志或重试逻辑?不用每个类都改,用接口 default 方法。
立即学习“Java免费学习笔记(深入)”;
- 在 Payment 接口中添加:
default void logBefore() { System.out.println("Start " + getClass().getSimpleName()); } - 所有已存在的实现类自动获得该方法,无需重写
- 调用时必须通过接口引用:
payment.logBefore();才能触发多态分派 - 若需定制化,搭配抽象钩子方法,例如
protected abstract String getTraceId();,由各子类决定
测试与替换要容易,说明多态已落地
如果单元测试还得启动真实微信 SDK 才能跑通支付逻辑,那说明多态没真正生效。
- 业务类只依赖接口,测试时可直接
@MockBean WeChatPayment或手动 new 一个空实现 - Spring 配置中切换 Bean 实现,比如把
EmailNotificationService换成MockNotificationService,上层无感知 - IDE 里按 Ctrl+Click 接口名,能立刻看到所有实现类——这是可扩展性的直观信号


















