谈谈我对DI的理解
本文中DI指依赖倒置。
依赖的概念
Baidu百科:依靠别人或事物而不能自立或自给。
软件开发中的依赖:依赖描述了两个模型元素之间的关系,如果被依赖的模型元素发生变化就会影响到另一个模型元素。
DI的概念
A. 上层模块不应该依赖于下层模块,它们共同依赖于一个抽象。
B. 抽象不能依赖于具象,具象依赖于抽象。
实例谈开
在分层开发中,通常会有这样的两个模块:DAL(数据访问层)和BLL(业务逻辑层) 。 下面就以电子商务系统中的 订单、产品、用户 为例来说说这两个模块之间的依赖关系。
正向依赖
DAL:
public class OrderDao
{
public List<Orders> GetOrderByUserID(int userid)
{
throw new NotImplementedException();
}
public List<Orders> GetOrderByProductID(int productID)
{
throw new NotImplementedException();
}
}
{
public List<Orders> GetOrderByUserID(int userid)
{
throw new NotImplementedException();
}
public List<Orders> GetOrderByProductID(int productID)
{
throw new NotImplementedException();
}
}
BLL:
public class Order
{
private OrderDao orderDao;//对DAL中OrderDao的引用
public Order(OrderDao orderDao)
{
orderDao = orderDao;
}
public List<Orders> GetOrderByUserID(int userid)
{
List<Orders> list = null;
list = orderDao.GetOrderByUserID(userid);
return list;
}
public List<Orders> GetOrderByProductID(int productID)
{
List<Orders> list = null;
list = orderDao.GetOrderByProductID(productID);
return list;
}
}
{
private OrderDao orderDao;//对DAL中OrderDao的引用
public Order(OrderDao orderDao)
{
orderDao = orderDao;
}
public List<Orders> GetOrderByUserID(int userid)
{
List<Orders> list = null;
list = orderDao.GetOrderByUserID(userid);
return list;
}
public List<Orders> GetOrderByProductID(int productID)
{
List<Orders> list = null;
list = orderDao.GetOrderByProductID(productID);
return list;
}
}
BLL中Order持有了DAL中OrderDao的引用,这个时候BLL模块依赖于DAL模块。他们之间构成了紧耦合。如果要更换DAL模块,显然需要修改BLL中的代码。
引入抽象
依赖倒置的思想告诉我们上层模块(BLL)和下层模块(DAL)都应当依赖于抽象。那么我们引入一个抽象模块。
抽象模块:
public interface IOrderDao
{
List<Orders> GetOrderByUserID(int userid);
List<Orders> GetOrderByProductID(int productID);
}
{
List<Orders> GetOrderByUserID(int userid);
List<Orders> GetOrderByProductID(int productID);
}
DAL:
public class OrderDao : IOrderDao//继承于抽象
{
public List<Orders> GetOrderByUserID(int userid)
{
throw new NotImplementedException();
}
public List<Orders> GetOrderByProductID(int productID)
{
throw new NotImplementedException();
}
}
{
public List<Orders> GetOrderByUserID(int userid)
{
throw new NotImplementedException();
}
public List<Orders> GetOrderByProductID(int productID)
{
throw new NotImplementedException();
}
}
BLL:
public class Order
{
private IOrderDao orderDao;//依赖于抽象
public Order(IOrderDao orderdao)
{
orderDao = orderdao;
}
public List<Orders> GetOrderByUserID(int userid)
{
List<Orders> list = null;
list = orderDao.GetOrderByUserID(userid);
return list;
}
public List<Orders> GetOrderByProductID(int productID)
{
List<Orders> list = null;
list = orderDao.GetOrderByProductID(productID);
return list;
}
}
{
private IOrderDao orderDao;//依赖于抽象
public Order(IOrderDao orderdao)
{
orderDao = orderdao;
}
public List<Orders> GetOrderByUserID(int userid)
{
List<Orders> list = null;
list = orderDao.GetOrderByUserID(userid);
return list;
}
public List<Orders> GetOrderByProductID(int productID)
{
List<Orders> list = null;
list = orderDao.GetOrderByProductID(productID);
return list;
}
}
现在BLL持有了对抽象模块的引用,而DAL也依赖于该抽象模块。抽象模块的引入消除了BLL和DAL之间的依赖。那么这种方法是否完美呢?
接口的单一性
在一个业务驱动的系统中,如果与订单相关的业务发生变化,会导致我们去修改 IOrderDao,相应的DAL中的OrderDao 和BLL的Order都会被修改。
什么原因呢?
上面的这种设计让我们无法保持一个稳定的接口。面向对象设计中,有这样的两个原则:
单一职责原则(SRP):保证对象的细粒度和单一性。
开放-封闭原则(OCP):对于扩展开放,对于更改封闭。
于是有了下面的设计。
抽象模块:
public interface IOrderUserDao
{
List<Orders> GetOrderByUserID(int userid);
}
public interface IOrderProductDao
{
List<Orders> GetOrderByProductID(int productID);
}
{
List<Orders> GetOrderByUserID(int userid);
}
public interface IOrderProductDao
{
List<Orders> GetOrderByProductID(int productID);
}
DAL:
public partial class OrderDao : IOrderUserDao
{
public List<Orders> GetOrderByUserID(int userid)
{
throw new NotImplementedException();
}
}
public partial class OrderDao : IOrderProductDao
{
public List<Orders> GetOrderByProductID(int productID)
{
throw new NotImplementedException();
}
}
{
public List<Orders> GetOrderByUserID(int userid)
{
throw new NotImplementedException();
}
}
public partial class OrderDao : IOrderProductDao
{
public List<Orders> GetOrderByProductID(int productID)
{
throw new NotImplementedException();
}
}
BLL:
public class User
{
private IOrderUserDao orderDao;//依赖于抽象
public User(IOrderUserDao orderdao)
{
orderDao = orderdao;
}
public List<Orders> GetOrderByUserID(int userid)
{
List<Orders> list = null;
list = orderDao.GetOrderByUserID(userid);
return list;
}
}
public class Product
{
private IOrderProductDao orderDao;//依赖于抽象
public Product(IOrderProductDao orderdao)
{
orderDao = orderdao;
}
public List<Orders> GetOrderByProductID(int productID)
{
List<Orders> list = null;
list = orderDao.GetOrderByProductID(productID);
return list;
}
}
{
private IOrderUserDao orderDao;//依赖于抽象
public User(IOrderUserDao orderdao)
{
orderDao = orderdao;
}
public List<Orders> GetOrderByUserID(int userid)
{
List<Orders> list = null;
list = orderDao.GetOrderByUserID(userid);
return list;
}
}
public class Product
{
private IOrderProductDao orderDao;//依赖于抽象
public Product(IOrderProductDao orderdao)
{
orderDao = orderdao;
}
public List<Orders> GetOrderByProductID(int productID)
{
List<Orders> list = null;
list = orderDao.GetOrderByProductID(productID);
return list;
}
}
那么您的意见呢?
-
- DeepSought
- 探索AI融入千行百业与日常生活
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
· 基于Microsoft.Extensions.AI核心库实现RAG应用
· Linux系列:如何用heaptrack跟踪.NET程序的非托管内存泄露
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 【译】Visual Studio 中新的强大生产力特性
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 【设计模式】告别冗长if-else语句:使用策略模式优化代码结构