2011-06-29 26 views
8

Wyobraź sobie, że istnieje klasa Customer z metodą instancji Load().Jak korzystać z iniekcji zależności przy użyciu metod statycznych?

Po wywołaniu metody Load() pobiera szczegóły zamówienia, np.

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

GetAll() jest metodą statyczną klasy Order i parametry wejściowe pola zdefiniowane w klasie Customer.

Jak widać, Order jest zależnością klasy Customer, jednak nie mogę po prostu utworzyć IOrder i wstrzyknąć go tam, ponieważ interfejsy nie mogą mieć statycznych metod.

Dlatego pytanie brzmi, w jaki sposób mogę wprowadzić wtrysk zależności w tym przykładzie?

Nie chcę, aby GetAll() metoda instancji, ponieważ jest to metoda statyczna i trzeba zachować to w ten sposób.

Na przykład użyłem klas użytkowych w moim projekcie, z których większość zawiera tylko metody statyczne.

Odpowiedz

9

Jeśli chcesz zachować statyczną metodę przez , będę owijać statyczne wywołania w obiekcie repozytorium.

Jak to:

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

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

Teraz wstrzyknąć tego repozytorium w swojej klasie Customer.

(jestem zakładając, że robisz to tak można wstrzykiwać fałszywe IOrders przy starcie dla celów testowych. Muszę powiedzieć, że ogólnie rzecz biorąc, metody statyczne są poważną przeszkodą w testowaniu.)

+0

Dzięki, czy te klasy repozytoriów i interfejsy będą częścią warstwy dostępu do danych? Moja klasa Order to jednostka biznesowa odwzorowana z tabeli Order (używając LINQ do SQL). –

+0

@ user133212 to tylko otoki wokół istniejącej funkcji. więc gdziekolwiek ta funkcja logicznie przynależy do warstwy, umieściłbym również opakowanie. –

3

Widząc jak Twój root agregujący do pobierania zamówień to model klienta, który byłby zdecydowanie radzę utworzyć repozytorium klienta i wstrzyknąć to do jakiejkolwiek usługi, która tego wymaga.

Oto przykład:

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

wskaźnik funkcji wtryskowa

TLDR:

wstrzyknąć wskaźnik funkcji do klasy Customer. Wartością tego wskaźnika funkcji może być Order.GetAll w produkcji i MockOrder.GetAll w testach.

PRZYKŁAD:

Zależność (problemy statyczne funkcja to zależeć)

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

Nasz grupa zależna (zależy Statyczny):

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

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

produkcji klasa klienta (wykonuje zależność injecti na):

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

Testowanie klasy klienta (jak testy jednostkowe można wstrzykiwać fałszywe zależność):

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

DYSKUSJA:

Jak faktycznie wstrzyknąć "wskaźnik funkcji" będzie zależy od składni i funkcji dostępnych w Twoim języku. Tutaj mówię tylko o ogólnej koncepcji.

To nie jest całkiem ładne rozwiązanie. Prawdopodobnie byłoby łatwiej, gdybyś mógł zmienić metodę na instancję (być może wprowadzając obiekt OrdersLoader lub używając odpowiedzi Paula Phillipsa). Ale jeśli naprawdę chcesz zachować to jako funkcję statyczną, to rozwiązanie zadziała.

Powiązane problemy