发布于2026-05-21 阅读(0)
扫一扫,手机访问
要让高层模块依赖抽象接口而不是具体实现,关键在于把“谁创建、谁调用、谁绑定”这三个环节从硬编码中抽离出来,转而通过契约(接口或抽象类)来组织关系。这听起来有点抽象,但实际操作起来,其实是一套非常清晰的组合拳。

接口可不是为了写而写,它的核心使命是提炼出稳定不变的行为契约。举个例子,设计一个订单服务,别一上来就琢磨OrderServiceImpl怎么写。正确的姿势是,先定义OrderService这个接口,只暴露create()、cancel()这些业务语义明确的方法。这样一来,无论是数据库版、内存版还是测试用的模拟版实现,都必须遵守同一个契约,变与不变就分得清清楚楚了。
在编写业务逻辑类(比如PaymentProcessor)时,要养成一个习惯:成员变量、方法参数、返回类型,统统使用接口类型。这意味着,要彻底告别在代码里直接new XxxServiceImpl()或者引用具体实现类名的做法。
private final OrderService orderService;private final OrderServiceImpl orderService;public void process(OrderService service)public void process(OrderServiceImpl service)这一步是建立依赖关系的“法律条文”,从声明上就杜绝了与具体实现的直接耦合。
实现类不应该由高层模块主动“new”出来,而是应该通过外部机制“送进去”。这就像是,高层模块只负责声明“我需要一个能处理订单的工具”,至于这个工具具体是谁、从哪来,它并不关心。常见的“送货”方式有这么几种:
public setXxx(Interface impl)方法,允许容器或测试代码在对象创建后再设置依赖。这种方式更灵活,但可能带来状态的不确定性。通过注入,高层模块完全不知道也不关心底层用的是MySQL还是Redis,只要送进来的对象实现了约定的接口,它就能正常工作。
那么,最终到底“送”哪个具体的实现类进去呢?这个决策权应该上交给框架或者配置。比如在Spring Boot中,你只需要给实现类加上@Service注解,如果需要指定默认实现,就用@Primary。想根据环境切换?用@Profile(“test”)就能轻松为测试环境配置一个模拟实现。
这样一来,高层模块的代码完全无需修改,仅仅通过外部配置,就能灵活切换数据源、日志组件、支付网关等具体实现。这不仅提升了代码的可测试性,也让系统在面对变化时,拥有了真正的弹性。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8