Back

什么是依赖倒置原则?简单解释

什么是依赖倒置原则?简单解释

依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计的五大SOLID原则之一。它通过改变依赖方向——从具体实现到抽象契约,帮助创建灵活、解耦的系统。本文将用通俗易懂的语言帮助你理解DIP,并提供可立即应用的示例。

要点

  • 高层模块不应依赖低层模块,两者都应依赖抽象
  • DIP使架构更灵活且可测试
  • 你将看到如何在多种语言中应用DIP的实际示例

官方定义

高层模块不应依赖低层模块。两者都应依赖抽象。抽象不应依赖细节。细节应依赖抽象。

让我们分解一下:

  • 高层模块:包含业务逻辑(例如下订单)
  • 低层模块:处理特定任务(例如发送电子邮件)
  • 抽象:定义行为而非实现的接口或基类

视觉类比

想象你有一个OrderService,当订单生成时发送电子邮件通知。

不使用DIP:

OrderService --> EmailService

OrderServiceEmailService紧密耦合。你无法轻易替换或模拟它。

使用DIP:

OrderService --> INotificationService <-- EmailService

现在两个模块都依赖于一个抽象(INotificationService)。

代码示例:不使用DIP(TypeScript)

class EmailService {
  send(message: string) {
    console.log(`Sending email: ${message}`);
  }
}

class OrderService {
  constructor(private emailService: EmailService) {}

  placeOrder() {
    this.emailService.send("Order placed");
  }
}

这使OrderServiceEmailService紧密耦合。

重构:使用DIP(TypeScript)

interface INotificationService {
  send(message: string): void;
}

class EmailService implements INotificationService {
  send(message: string) {
    console.log(`Sending email: ${message}`);
  }
}

class OrderService {
  constructor(private notifier: INotificationService) {}

  placeOrder() {
    this.notifier.send("Order placed");
  }
}

Python中的DIP

from abc import ABC, abstractmethod

class NotificationService(ABC):
    @abstractmethod
    def send(self, message: str):
        pass

class EmailService(NotificationService):
    def send(self, message: str):
        print(f"Sending email: {message}")

class OrderService:
    def __init__(self, notifier: NotificationService):
        self.notifier = notifier

    def place_order(self):
        self.notifier.send("Order placed")

# 使用方式
service = OrderService(EmailService())
service.place_order()

Java中的DIP

interface NotificationService {
    void send(String message);
}

class EmailService implements NotificationService {
    public void send(String message) {
        System.out.println("Sending email: " + message);
    }
}

class OrderService {
    private NotificationService notifier;

    public OrderService(NotificationService notifier) {
        this.notifier = notifier;
    }

    public void placeOrder() {
        notifier.send("Order placed");
    }
}

// 使用方式
OrderService service = new OrderService(new EmailService());
service.placeOrder();

为什么DIP很重要

  • 可测试性:可以用模拟对象或假对象替换真实依赖
  • 灵活性:无需修改高层逻辑即可切换实现
  • 关注点分离:每个模块只做一项工作,通过契约进行通信

常见误解:DIP ≠ 依赖注入

它们相关但不相同:

  • DIP是关于谁依赖于谁(依赖方向)
  • 依赖注入是应用DIP的一种方式——通过注入依赖而非硬编码它们

何时使用DIP

在以下情况使用:

  • 你想编写不关心底层实现的业务逻辑
  • 你正在开发分层或模块化应用
  • 你正在构建可测试或可扩展的系统

结论

依赖倒置原则是关于颠倒通常的依赖方向——使抽象而非实现定义你的架构。它使你的代码更可重用、可测试,并且对变化更具弹性。

常见问题

这是一种设计原则,高层模块和低层模块都依赖于抽象,而不是相互依赖。

不是。DIP是一个原则。依赖注入是实现DIP的一种技术。

因为你可以用遵循相同接口的模拟对象或存根替换真实依赖。

在TypeScript中接口很有帮助,但在JavaScript中你可以使用对象形状契约和模式来达到相同效果。

Listen to your bugs 🧘, with OpenReplay

See how users use your app and resolve issues fast.
Loved by thousands of developers