写程序时,我们常遇到这种情况:一个类需要用到另一个类的功能。比如做外卖系统,订单服务需要发短信通知用户。最直接的做法是在订单类里直接创建短信类的实例。
可问题来了,要是哪天不想发短信,想改发微信推送呢?就得去改订单类的代码。这显然不太灵活,也违反了“开闭原则”——对扩展开放,对修改关闭。
依赖注入登场
依赖注入(Dependency Injection,简称 DI)就是为了解决这个问题。它把对象的创建权交给外部,而不是在类内部自己 new。这样,类只需要“用”,不用管“怎么来”。
来看个简单的 Java 例子:
public interface Notifier {
void send(String message);
}
public class SmsNotifier implements Notifier {
public void send(String message) {
System.out.println("发送短信:" + message);
}
}
public class WeChatNotifier implements Notifier {
public void send(String message) {
System.out.println("发送微信:" + message);
}
}
上面定义了一个通知接口和两种实现方式。接下来是订单服务类:
public class OrderService {
private Notifier notifier;
// 构造函数注入
public OrderService(Notifier notifier) {
this.notifier = notifier;
}
public void placeOrder() {
System.out.println("订单已创建");
notifier.send("您的订单已下单成功");
}
}
注意这里没有在 OrderService 里 new SmsNotifier,而是通过构造函数传进来。这个“传进来”的过程,就是依赖注入。
使用的时候可以这样:
public class Main {
public static void main(String[] args) {
Notifier sms = new SmsNotifier();
OrderService service = new OrderService(sms);
service.placeOrder();
}
}
如果想换微信推送,只需要改一行:
Notifier wechat = new WeChatNotifier();
OrderService service = new OrderService(wechat);
不需要动 OrderService 的代码。这种设计让程序更容易维护和测试。比如测试时可以用一个 Mock 的通知器,避免真实发消息。
实际开发中,像 Spring 框架会自动完成依赖注入,开发者只需要加个 @Autowired 注解,框架就会把合适的对象“塞”进去。但理解底层原理,才能用得更明白。