How to use Dependency Injection with Static Methods?
假设有一个带有实例
当调用
1 | var orders = Order.GetAll(customerId, ...); |
如您所见,
因此,问题是我如何在这个例子中引入依赖注入?
我不想让
例如,我在设计中使用了实用程序类,其中大多数只包含静态方法。
如果必须保留静态方法,我将把静态调用包装在一个存储库对象中。
这样地:
1 2 3 4 5 6 7 8 9 10 | interface IOrderRepository { IEnumerable<IOrder> GetAll(customerId, ..); } class OrderRepository : IOrderRepository { IEnumerable<IOrder> GetAll(customerId, ...) { Order.GetAll(customerId,...); // The original static call. } } |
现在您将这个存储库注入到您的
(我假设您这样做是为了在运行时为测试目的注入假IOR。一般来说,静态方法是测试的一个严重障碍。)
将获取订单的聚合根视为您的客户模型,我强烈建议您创建一个客户存储库,并将其注入到任何服务需要它的地方。
下面是一个例子:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | public class CustomerService { private readonly ICustomerRepository _customerRepository; public CustomerService(ICustomerRepository customerRepository) { if (customerRepository == null) { throw new ArgumentNullException("customerRepository"); } _customerRepository = customerRepository; } public IEnumerable<IOrder> GetOrdersForCustomerId(int customerId) { return _customerRepository.GetOrdersForCustomerId(customerId); } } public interface ICustomerRepository { IEnumerable<IOrder> GetOrdersForCustomerId(int customerId); } class CustomerRepository : ICustomerRepository { public IEnumerable<IOrder> GetOrdersForCustomerId(int customerId) { throw new NotImplementedException(); } } |
函数指针注入
TLDR:
向
例子:
依赖项(我们依赖的有问题的静态函数):
1 2 3 4 5 6 | class Order { static func GetAll() -> [Order] { var orders = ... // Load from production source return orders } } |
我们的从属类(取决于静态函数):
1 2 3 4 5 6 7 8 9 10 | class Customer { func Init(getAllOrdersFunction) { // Arg is a func pointer self.getAllOrdersFunction = getAllOrdersFunction } func Load() { var orders = self.getAllOrdersFunction() // Do stuff... } } |
生产客户端类(执行依赖项注入):
1 2 3 4 5 6 7 | class BusinessLogicManager { func DoBusinessLogic() { var customer = Customer(Order.GetAll) // Prod func injected here customer.Load() // Do stuff... } } |
测试客户端类(单元测试如何插入假依赖项):
1 2 3 4 5 6 7 8 9 10 11 12 | class CustomerUnitTests { static func GetFakeOrders() { var orders = ... // Hardcoded test data return orders } func TestLoad() { var customer = Customer(CustomerUnitTests.GetFakeOrders) // Fake func injected here customer.Load() // Verify results given known behavior of GetFakeOrders } } |
讨论:
实际注入"函数指针"的方式将取决于您的语言中可用的语法和功能。在这里我只讲一般概念。
这不是一个很好的解决方案。如果您可以将