2011-06-29 38 views
8

想象一下有一个Customer类与实例Load()方法。如何在静态方法中使用依赖注入?

Load()方法被调用时,它通过例如检索订单细节。

var orders = Order.GetAll(customerId, ...); 

GetAll()Order类的静态方法和输入参数在Customer类定义的字段。

正如你所看到的,OrderCustomer类的依赖,但是,我不能只是创建一个IOrder,并注入它那里接口不能有静态方法。

因此,问题是我怎么能在这个例子中引入依赖注入?

我不想让GetAll()成为一个实例方法,因为它是一个静态方法,需要保持这种方法。

例如,我在我的设计中使用了实用程序类,其中大部分只包含静态方法。

回答

9

如果必须保持静态方法,我想包库中存储的对象静态调用。

像这样:

interface IOrderRepository { 
    IEnumerable<IOrder> GetAll(customerId, ..); 
} 

class OrderRepository : IOrderRepository { 
    IEnumerable<IOrder> GetAll(customerId, ...) 
    { 
    Order.GetAll(customerId,...); // The original static call. 
    } 
} 

现在你注入这个仓库到你的Customer类。

(我假设你正在做这个,所以你可以在运行时为测试目的注入假IOrders。我应该说,在一般情况下,静态方法是一个严重的障碍测试。)

+0

谢谢,这些存储库类和接口是否会成为数据访问层的一部分?我的订单类是从订单表(使用LINQ to SQL)映射的业务实体。 –

+0

@ user133212它只是您现有功能的包装。所以无论该函数在逻辑上属于分层的地方,我也会把这个包装器。 –

3

鉴于你获取订单的聚合根是您的客户模型我会强烈建议您创建一个客户存储库并将其注入到任何需要它的服务中。

下面是一个例子:

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(); 
    } 
} 
0

函数指针注射

TLDR:

注入一个函数指针到Customer类。该函数指针的值可以是生产中的Order.GetAll,测试中可以是MockOrder.GetAll

例:

的依赖性(我们依靠问题的静态函数):

class Order { 
    static func GetAll() -> [Order] { 
     var orders = ... // Load from production source 
     return orders 
    } 
} 

我们依赖类(取决于静态函数):

class Customer { 
    func Init(getAllOrdersFunction) { // Arg is a func pointer 
     self.getAllOrdersFunction = getAllOrdersFunction 
    } 

    func Load() { 
     var orders = self.getAllOrdersFunction() 
     // Do stuff... 
    } 
} 

生产客户端类()执行依赖注入在):

class BusinessLogicManager { 
    func DoBusinessLogic() { 
     var customer = Customer(Order.GetAll) // Prod func injected here 
     customer.Load() 
     // Do stuff... 
    } 
} 

测试客户端类(单元测试是如何注入假的依赖):

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 
    } 
} 

讨论:

你怎么竟注入 “函数指针” 将取决于您的语言提供的语法和功能。这里我只是谈论一般概念。

这不完全是一个漂亮的解决方案。如果您可以将GetAll更改为实例方法(可能通过引入OrdersLoader对象或使用Paul Phillips的答案),那可能会更容易一些。但是如果你真的想把它保持为一个静态函数,那么这个解决方案就可以工作。