依赖注入的英文翻译是 Dependency Injection,缩写为 DI
。对于这个概念,有一个非常形象的说法,那就是:依赖注入是一个标价 25 美元,实际上只值 5 美分的概念。也就是说,这个概念听起来很“高大上”,实际上,理解、应用起来非常简单。
那到底什么是依赖注入呢?我们用一句话来概括就是:不通过 new() 的方式在类内部创建依赖类对象,而是将依赖的类对象在外部创建好之后,通过构造函数、函数参数等方式传递(或注入)给类使用
。
我们还是通过一个例子来解释一下。在这个例子中,Notification 类
负责消息推送,依赖MessageSender 类
实现推送商品促销、验证码等消息给用户。我们分别用依赖注入和非依赖注入两种方式来实现一下。具体的实现代码如下所示:
// 非依赖注入实现方式public class Notification {private MessageSender messageSender;public Notification() {this.messageSender = new MessageSender(); //此处有点像hardcode}public void sendMessage(String cellphone, String message) {//...省略校验逻辑等...this.messageSender.send(cellphone, message);}}public class MessageSender {public void send(String cellphone, String message) {//....}}// 使用NotificationNotification notification = new Notification();// 依赖注入的实现方式public class Notification {private MessageSender messageSender;// 通过构造函数将messageSender传递进来public Notification(MessageSender messageSender) {this.messageSender = messageSender;}public void sendMessage(String cellphone, String message) {//...省略校验逻辑等...this.messageSender.send(cellphone, message);}}//使用NotificationMessageSender messageSender = new MessageSender();Notification notification = new Notification(messageSender);
通过依赖注入的方式来将依赖的类对象传递进来,这样就提高了代码的扩展性,我们可以灵活地替换依赖的类
。这一点在我们之前讲“开闭原则”的时候也提到过。当然,上面代码还有继续优化的空间,我们还可以把 MessageSender 定义成接口,基于接口而非实现编程。改造后的代码如下所示:
public class Notification {private MessageSender messageSender;public Notification(MessageSender messageSender) {this.messageSender = messageSender;}public void sendMessage(String cellphone, String message) {this.messageSender.send(cellphone, message);}}public interface MessageSender {void send(String cellphone, String message);}// 短信发送类public class SmsSender implements MessageSender {@Overridepublic void send(String cellphone, String message) {//....}}// 站内信发送类public class InboxSender implements MessageSender {@Overridepublic void send(String cellphone, String message) {//....}}//使用NotificationMessageSender messageSender = new SmsSender();Notification notification = new Notification(messageSender);
实际上,你只需要掌握刚刚举的这个例子,就等于完全掌握了依赖注入。尽管依赖注入非常简单,但却非常有用,在后面的章节中,我们会讲到,它是编写可测试性代码最有效的手段。
思考
为什么要使用依赖注入? – 降低耦合性总结
依赖注入就是在外部创建好类,然后通过构造函数或者函数参数,传递给需要的类参考
19 | 理论五:控制反转、依赖反转、依赖注入,这三者有何区别和联系?