实现步骤
- 定义接口:为依赖的每个服务定义接口。例如,如果复杂业务逻辑类
ComplexBusinessLogic
依赖用户服务和订单服务,分别定义 IUserService
和 IOrderService
接口,接口中声明业务逻辑类会调用的方法。
public interface IUserService
{
User GetUserById(int id);
}
public interface IOrderService
{
Order GetOrderById(int id);
}
- 在复杂业务逻辑类中通过构造函数注入依赖:修改
ComplexBusinessLogic
类,通过构造函数接受依赖的接口实例。
public class ComplexBusinessLogic
{
private readonly IUserService _userService;
private readonly IOrderService _orderService;
public ComplexBusinessLogic(IUserService userService, IOrderService orderService)
{
_userService = userService;
_orderService = orderService;
}
public void SomeComplexMethod()
{
// 使用 _userService 和 _orderService 完成复杂业务逻辑
var user = _userService.GetUserById(1);
var order = _orderService.GetOrderById(1);
// 进一步处理逻辑
}
}
- 在单元测试中创建模拟对象并注入:使用如 Moq 这样的模拟框架,在单元测试中创建模拟的服务接口实例,并通过构造函数注入到
ComplexBusinessLogic
实例中。
using Moq;
using NUnit.Framework;
[TestFixture]
public class ComplexBusinessLogicTests
{
[Test]
public void TestSomeComplexMethod()
{
var mockUserService = new Mock<IUserService>();
var mockOrderService = new Mock<IOrderService>();
mockUserService.Setup(s => s.GetUserById(1)).Returns(new User());
mockOrderService.Setup(s => s.GetOrderById(1)).Returns(new Order());
var complexLogic = new ComplexBusinessLogic(mockUserService.Object, mockOrderService.Object);
complexLogic.SomeComplexMethod();
mockUserService.Verify(s => s.GetUserById(1), Times.Once);
mockOrderService.Verify(s => s.GetOrderById(1), Times.Once);
}
}
好处
- 解耦依赖:复杂业务逻辑类不再直接依赖具体的服务实现,降低了类与类之间的耦合度,提高了代码的可维护性和可扩展性。例如,当
IUserService
的具体实现发生变化时,只要接口不变,ComplexBusinessLogic
类不需要修改。
- 便于单元测试:可以创建模拟对象来替换真实的依赖服务,使得测试可以专注于复杂业务逻辑类本身的功能,避免了因依赖服务的不可用或不稳定导致测试失败。例如,在上述测试中,不依赖真实的用户服务和订单服务即可测试
ComplexBusinessLogic
的 SomeComplexMethod
方法。
- 提高代码的可复用性:由于依赖通过接口注入,不同的业务场景可以使用不同的实现来满足依赖,提高了代码的复用性。例如,在不同的模块中,只要实现了
IUserService
接口,都可以注入到依赖该接口的类中。