设计模式是对相关问题提出的解决方案。
一般而言,一个模式有四个基本要素:
- 模式名称 (pattern name) 一个助记名,它用一两个词语来描述模式问题、解决方案和效果。
- 问题(problem)描述了应该在何时使用模式,解释了问题存在的前因后果。
- 解决方案(solution)描述了设计的组成成分,它们之间的相互关系以及各自的职责和协作方式。
- 效果(consequence)描述了模式应用的效果以及使用模式应权衡的问题。
定义
依赖倒置原则 (Dependency Inversion Principle
,DIP
)是编程开发中的一个重要原则,具体指抽象不应该依赖于具体类,具体类应当依赖于抽象 。
换言之,要针对接口编程,而不是针对实现编程,旨在降低模块间的耦合度,提高系统的可维护性和稳定性。
核心思想
DIP的核心思想是:高层模块不应该依赖低层模块,两者都应该依赖抽象。抽象不应该依赖细节,细节应该依赖抽象。这意味着在编程时,我们应该针对抽象进行编程,而不是针对具体的实现进行编程。这样可以降低客户与实现模块间的耦合,提高系统的稳定性和可重用性。
要求
依赖倒转原则要求我们在程序代码中传递参数时或在关联关系中,尽量引用层次高的抽象层类,即使用接口和抽象类进行变量类型声明、参数类型声明、方法返回类型声明,以及数据类型的转换等,而不要用具体类来做这些事情。为了确保该原则的应用,一个具体类应当只实现接口或抽象类中声明过的方法,而不要给出多余的方法,否则将无法调用到在子类中增加的新方法。
优点
采用依赖倒置原则有以下优点:
- 减少类间的耦合性:通过依赖抽象而不是具体实现,可以降低模块之间的耦合度,使得系统更加灵活和可扩展。
- 提高系统的稳定性:通过依赖抽象,可以减少因低层模块变更对高层模块的影响,从而提高系统的稳定性。
- 提高代码的可读性和可维护性:降低模块间的直接依赖关系,使得代码更加清晰和易于维护。
在实际应用中,DIP可以通过以下方式实现:
高层模块和低层模块都依赖于抽象:通过定义接口或抽象类,高层模块和低层模块都依赖于这些抽象,而不是直接依赖于对方。这样可以降低模块间的耦合度,提高系统的可维护性和可扩展性。
使用依赖注入:依赖注入是一种具体实现方法,通过将依赖关系交给外部进行注入,可以进一步降低模块间的耦合度,使得系统更加灵活和可扩展。
简单案例
- 定义抽象接口
首先定义一个抽象接口或基类,这个接口或基类定义了一组方法,这些方法是所有具体实现都需要遵循的契约。
javascript
// 抽象接口
class MessageSender {
send(message) {
throw new Error('Method "send" must be implemented.');
}
}
- 创建具体实现
然后创建具体的类来实现上述抽象接口。
javascript
// 具体实现
class EmailSender extends MessageSender {
send(message) {
console.log(`Sending email: ${message}`);
}
}
class SmsSender extends MessageSender {
send(message) {
console.log(`Sending SMS: ${message}`);
}
}
- 使用依赖注入
接下来,在需要发送消息的业务逻辑中,我们不直接创建EmailSender或SmsSender实例,而是通过构造函数或setter方法注入这些依赖。
javascript
class NotificationService {
constructor(sender) {
this.sender = sender;
}
notify(message) {
this.sender.send(message);
}
}
- 使用示例
现在我们可以根据不同的需求来注入不同的消息发送器。
javascript
const emailSender = new EmailSender();
const smsSender = new SmsSender();
const notificationService = new NotificationService(emailSender);
notificationService.notify('Welcome to our service!'); // 输出: Sending email: Welcome to our service!
// 更换发送方式
notificationService.sender = smsSender;
notificationService.notify('Welcome to our service!'); // 输出: Sending SMS: Welcome to our service!
总结:依赖倒置原则
- 高层次的模块不应该依赖于低层次的模块,他们都应该依赖于抽象。
- 抽象不应该依赖于具体,具体应该依赖于抽象。