当前位置: 首页 > news >正文

[C#]什么是依赖倒置原则:依赖倒置原则的简单示例与应用解析

依赖倒置原则(Dependency Inversion Principle,DIP)是面向对象设计的一个重要原则,是SOLID五大设计原则之一。它旨在减少模块之间的依赖性,使得代码更加灵活、可扩展、可维护。依赖倒置原则有两个核心思想:

  1. 高层模块不应该依赖低层模块,二者都应该依赖于抽象。

    • 高层模块指的是那些包含应用程序核心逻辑的模块,而低层模块则是那些具体的实现细节或基础设施,如数据库访问、文件系统操作等。按照依赖倒置原则,这些模块应该通过依赖抽象(如接口或抽象类)来解耦,而不是直接依赖具体实现。
  2. 抽象不应该依赖于细节,细节应该依赖于抽象。

    • 这意味着定义应用程序行为的抽象(如接口或抽象类)不应该依赖于实现细节(如具体类),而是具体类应该依赖于这些抽象。通过这种方式,可以在不影响高层模块的情况下,替换或修改低层模块的实现。

示例 1: 发送邮件

假设我们有一个日志记录模块(Logger)和一个邮件通知模块(EmailNotifier)。传统设计可能是这样:

public class Logger {public void Log(string message) {// 写入日志文件}
}public class EmailNotifier {private Logger logger = new Logger(); // 直接依赖于具体实现类public void SendEmail(string email, string message) {// 发送邮件logger.Log("Email sent to " + email);}
}

在这个例子中,EmailNotifier 依赖于 Logger 的具体实现。如果以后想换成数据库记录日志,而不是写入文件,就需要修改 EmailNotifier 的代码,这就导致了高层模块对低层模块的紧耦合。

为了遵循依赖倒置原则,可以这样改造:

public interface ILogger {void Log(string message);
}public class FileLogger : ILogger {public void Log(string message) {// 写入日志文件}
}public class EmailNotifier {private ILogger logger;public EmailNotifier(ILogger logger) {this.logger = logger;}public void SendEmail(string email, string message) {// 发送邮件logger.Log("Email sent to " + email);}
}

在这个改进后的设计中,EmailNotifier 依赖于抽象的 ILogger 接口,而不是具体的 FileLogger 实现类。通过这种方式,我们可以轻松替换 FileLogger 为其他日志记录实现,而无需修改 EmailNotifier 的代码。这就遵循了依赖倒置原则,使代码更具灵活性和可扩展性。

示例 2: 支付方式

假设我们有一个购物系统,支持不同的支付方式,如信用卡支付和 PayPal 支付。传统设计可能直接依赖于具体的支付类:

public class CreditCardPayment {public void ProcessPayment(decimal amount) {// 处理信用卡支付}
}public class PayPalPayment {public void ProcessPayment(decimal amount) {// 处理 PayPal 支付}
}public class ShoppingCart {private CreditCardPayment creditCardPayment = new CreditCardPayment();public void Checkout(decimal amount) {creditCardPayment.ProcessPayment(amount);}
}

在这个例子中,ShoppingCart 类直接依赖于 CreditCardPayment 类,如果我们想换成 PayPal 支付,就需要修改 ShoppingCart 类的代码。

使用依赖倒置原则,我们可以引入一个抽象的支付接口,然后在 ShoppingCart 中依赖这个接口,而不是具体的支付类:

public interface IPaymentProcessor {void ProcessPayment(decimal amount);
}public class CreditCardPayment : IPaymentProcessor {public void ProcessPayment(decimal amount) {// 处理信用卡支付}
}public class PayPalPayment : IPaymentProcessor {public void ProcessPayment(decimal amount) {// 处理 PayPal 支付}
}public class ShoppingCart {private IPaymentProcessor paymentProcessor;public ShoppingCart(IPaymentProcessor paymentProcessor) {this.paymentProcessor = paymentProcessor;}public void Checkout(decimal amount) {paymentProcessor.ProcessPayment(amount);}
}

这样一来,无论是使用信用卡支付还是 PayPal 支付,ShoppingCart 类都不需要修改,只需传入不同的支付处理实现即可。

示例 3: 数据存储

假设我们有一个应用程序,需要将数据保存到不同的存储系统中,如文件或数据库。传统设计可能是直接依赖于具体的存储类:

public class FileStorage {public void SaveData(string data) {// 保存数据到文件}
}public class DataHandler {private FileStorage storage = new FileStorage();public void HandleData(string data) {storage.SaveData(data);}
}

在这个例子中,DataHandler 直接依赖于 FileStorage 类。如果我们想换成数据库存储,就需要修改 DataHandler 的代码。

通过依赖倒置原则,可以这样设计:

public interface IStorage {void SaveData(string data);
}public class FileStorage : IStorage {public void SaveData(string data) {// 保存数据到文件}
}public class DatabaseStorage : IStorage {public void SaveData(string data) {// 保存数据到数据库}
}public class DataHandler {private IStorage storage;public DataHandler(IStorage storage) {this.storage = storage;}public void HandleData(string data) {storage.SaveData(data);}
}

现在,DataHandler 不再依赖于具体的存储实现,而是依赖于一个抽象的 IStorage 接口。我们可以在运行时选择不同的存储方式,而不需要修改 DataHandler 的代码。

你学废了麽?


http://www.mrgr.cn/news/833.html

相关文章:

  • c语言开源库之uthash用法
  • 使用EasyExcel填充Excel并上传至OSS
  • 使用docker compose一键部署MySQL服务
  • Tmagic-editor低代码底层拖拽库Moveable示例学习
  • 微信小程序中实现自动滚动
  • 白盒测试-发送请求
  • Java重修笔记 第三十六天 System类、大数据处理方案
  • 配置mysql5.7环境+使用python管理数据库+使用中间件mycat配置读写分离
  • 使用go实现一个简单的聊天服务器
  • 白骑士的C#教学实战项目篇 4.4 游戏开发
  • 优化大量数据导出到Excel的内存消耗(二):如果数据超出Excel单表上限,则进行分表
  • 前端面试题(二十五)|附赠完整面试流程
  • Python爬虫使用实例
  • Python 文件目录操作,以及json.dump() 和 json.load()
  • 安全自动化和编排:如何使用自动化工具和编排技术来提高安全操作效率。(第一篇)
  • k8s配置资源管理
  • 大学生科创项目在线管理系统的设计与实现
  • 宠物空气净化器推荐买吗?清除浮毛的效果好吗
  • LMDeploy 部署 VLMs 的方法与探讨
  • SuccBI+低代码文档中心 —数据管理