2010-07-26 5 views
5

У меня немного проблемы с сортировкой способа управления автоматическими разрешенными и ручными зависимостями в моих классах.Устранение автоматических и ручных зависимостей

Предположим, у меня есть два класса для расчета цен: один рассчитывает, сколько я буду взимать за доставку, а другой - сколько я буду взимать плату за весь заказ. Второй использует первый, чтобы суммировать стоимость доставки по всей цене заказа.

Оба класса имеют зависимость от третьего класса, который я буду называть ExchangeRate, который дает мне курс обмена, который я должен использовать для расчета цены.

До сих пор мы эту цепочку зависимостей:

OrderCalculator -> ShippingCalculator -> ExchangeRate

I'm с помощью Ninject для решения этих зависимостей, и это не работает до сих пор. Теперь у меня есть требование, чтобы скорость, возвращаемая классом ExchangeRate, будет меняться в зависимости от параметра, который будет предоставлен в конструкторе (поскольку объект не будет работать без этого, поэтому, чтобы заставить явную зависимость быть помещенной в конструктор) с пользовательского ввода. Из-за этого я больше не могу разрешать свои зависимости автоматически.

Всякий раз, когда я хочу, чтобы OrderCalculator или любые другие классы, которые зависят от ExchangeRate, я не могу попросить контейнер Ninject разрешить его мне, поскольку мне нужно предоставить параметр в конструкторе.

Что вы предлагаете в этом случае?

Спасибо!

EDIT: Давайте добавим некоторый код

Эта цепочка объектов потребляется службы WCF и я использую Ninject как контейнер DI.

 
public class OrderCalculator : IOrderCalculator 
{ 
     private IExchangeRate _exchangeRate; 
     public OrderCalculator(IExchangeRate exchangeRate) 
     { 
       _exchangeRate = exchangeRate; 
     } 
     public decimal CalculateOrderTotal(Order newOrder) 
     { 
       var total = 0m; 
       foreach(var item in newOrder.Items) 
       { 
         total += item.Price * _exchangeRate.GetRate(); 
       } 
       return total;    
     } 
} 

public class ExchangeRate : IExchangeRate 
{ 
     private RunTimeClass _runtimeValue; 
     public ExchangeRate(RunTimeClass runtimeValue) 
     { 
       _runtimeValue = runtimeValue; 
     } 
     public decimal GetRate() 
     { 
       //returns the rate according to _runtimeValue 
       if(_runtimeValue == 1) 
         return 15.3m; 
       else if(_runtimeValue == 2) 
         return 9.9m 
       else 
         return 30m; 
     } 
} 

//WCF Service 
public decimal GetTotalForOrder(Order newOrder, RunTimeClass runtimeValue) 
{ 
    //I would like to pass the runtimeValue when resolving the IOrderCalculator depedency using a dictionary or something 
    //Something like this ObjectFactory.Resolve(runtimeValue); 
    IOrderCalculator calculator = ObjectFactory.Resolve();  
    return calculator.CalculateOrderTotal(newOrder);  
} 

ответ

1

Я закончил делать что-то совершенно другое.

Прежде чем я вызову ObjectFactory для разрешения зависимостей для меня, я создаю новый экземпляр IExchangeRate, используя runTimeValue, и скажу, что контейнер IoC/DI использует его вместо создания нового. Таким образом, целая цепь объектов сохраняется и нет необходимости в фабриках.


//WCF Service 
public decimal GetTotalForOrder(Order newOrder, RunTimeClass runtimeValue) 
{ 
    IExchangeRate ex = new ExchangeRate(runtimeValue); 
    IOrderCalculator calculator = ObjectFactory.With<IExchangeRate>(ex).GetInstance(); 
    return calculator.CalculateOrderTotal(newOrder);  
} 

Но поскольку Ninject не есть способ сделать это (только пересвяжите, который не то, что я хочу) Я изменил свой контейнер StructureMap.

Спасибо, ребята, за вашу помощь! Действительно ценю это!

0

Переместить эту инициализацию из конструктора.

7

Как всегда, если у вас есть частичная зависимость от значения времени выполнения, the solution is an Abstract Factory.

Что-то, как это должно работать:

public interface IExchangeRateFactory 
{ 
    ExchangeRate GetExchangeRate(object runTimeValue); 
} 

Теперь инжектировать IExchangeRateFactory в ваших потребителей вместо ExchangeRate и использовать метод GetExchangeRate для преобразования значения времени выполнения для экземпляра ExchangeRate.

Очевидно, что вам также необходимо обеспечить реализацию IExchangeRateFactory и настроить NInject для сопоставления интерфейса с вашей реализацией.

+0

Давайте посмотрим, понял ли я. Мой OrderCalculator/ShippingCalculator должен получить объект (IExchangeRateFactory), способный создать класс ExchangeRate и вызвать GetExchangeRate, передающий параметр времени выполнения, правильно? Если да, то параметр runTimeValue станет тем, что должен заботиться OrderCalculator/ShippingCalculator, и я бы хотел, чтобы это не произошло. – tucaz

+0

Если * none * из них должны иметь дело со значением времени выполнения, то откуда это взялось? –

+0

Я понимаю, что вы говорите, но если мне это нравится, то что-то (runTimeValue), которое было только зависимостью от ExchangeRate, также станет зависимым от того, что другие классы используют его. Я ищу способ передать этот runTimeValue в контейнер DI и позволить ему заботиться о создании объекта. – tucaz

0

обновляется на основе кода:

//WCF Service 
public decimal GetTotalForOrder(Order newOrder, RunTimeClass runtimeValue) 
{ 
    //I would like to pass the runtimeValue when resolving the IOrderCalculator depedency using a dictionary or something 
    //Something like this ObjectFactory.Resolve(runtimeValue); 
    IOrderCalculator calculator = ObjectFactory.Resolve();  
    return calculator.CalculateOrderTotal(newOrder);  
} 

Обратите внимание, как этот метод только хочет runtimeValue так, что он может передать его на что-то другое? Это происходит из-за того, что функции построения объектов и выполнения задач неоднозначны. Я думаю, вы должны просить IOrderCalculator в конструкторе для этого метода.

Так что этот метод становится просто:

//WCF Service 
public decimal GetTotalForOrder(Order newOrder, IOrderCalculator calculator) 
{ 
    return calculator.CalculateOrderTotal(newOrder);  
} 

Теперь, когда вы строите свой IOrderCalculator вы должны пройти runtimeValue на это конструктор. Это немного сложно ответить, когда мы не знаем, что такое runtimeValue или откуда оно взялось.

+0

Он работает, но тогда этот параметр также станет зависимым от того, кто использует ExchangeRate, когда это не так. – tucaz

+0

runTimeValue - это параметр INT с идентификатором страны/штата/города, который используется для определения применяемой ставки налога, и он исходит из вызова метода WCF. Вот почему он доступен только во время выполнения, а также почему я не могу использовать его в создании службы WCF для построения IOrderCalculator. Он доступен только после создания WCF. – tucaz

+0

В этом случае ответ Марк Сееманн прав. –

Смежные вопросы