2010-07-26 34 views
5

Tôi đang gặp một chút rắc rối khi sắp xếp một cách để quản lý các phụ thuộc tự động được giải quyết và thủ công trong các lớp học của mình.Giải quyết các phụ thuộc tự động và thủ công

Giả sử tôi có hai lớp để tính giá: một tính toán số tiền tôi sẽ tính phí cho giao hàng và số tiền khác tôi sẽ tính phí cho toàn bộ đơn đặt hàng. Thứ hai sử dụng giá trị đầu tiên để tính tổng giá vận chuyển cho toàn bộ giá đặt hàng.

Cả hai lớp đều phụ thuộc vào lớp thứ ba mà tôi sẽ gọi cho ExchangeRate mang lại cho tôi tỷ giá hối đoái tôi nên sử dụng để tính giá.

Cho đến nay chúng tôi có dây chuyền này phụ thuộc:

OrderCalculator -> ShippingCalculator -> ExchangeRate

tôi đang sử dụng Ninject để giải quyết những sự phụ thuộc và điều này đã làm việc cho đến bây giờ. Bây giờ tôi có một yêu cầu rằng tốc độ được trả về bởi lớp ExchangeRate sẽ thay đổi theo một tham số sẽ được cung cấp trong Constructor (vì đối tượng sẽ không làm việc mà không có điều này, để làm cho phụ thuộc rõ ràng nó được đặt trên constructor) từ đầu vào của người dùng. Do đó tôi không còn có thể tự động giải quyết các phụ thuộc của mình nữa.

Bất cứ khi nào tôi muốn OrderCalculator hoặc bất kỳ lớp nào khác phụ thuộc vào ExchangeRate, tôi không thể yêu cầu thùng chứa Ninject giải quyết nó cho tôi vì tôi cần cung cấp tham số trong hàm tạo.

Bạn đề xuất gì trong trường hợp này?

Cảm ơn!

EDIT: Hãy thêm một số mã

chuỗi này của các đối tượng được tiêu thụ bởi một dịch vụ WCF và tôi đang sử dụng Ninject như container 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);  
} 

Trả lời

1

Tôi đã kết thúc một việc hoàn toàn khác.

Trước khi tôi gọi ObjectFactory để giải quyết các phụ thuộc cho tôi, tôi tạo một thể hiện mới của IExchangeRate bằng cách sử dụng runTimeValue và cho biết thùng chứa IoC/DI sử dụng nó thay vì tạo một cái mới. Bằng cách này, toàn bộ chuỗi các đối tượng được bảo tồn và không có nhu cầu cho các nhà máy.


//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);  
} 

Nhưng vì Ninject không có cách nào để làm điều này (chỉ Rebind không phải là thứ tôi muốn) Tôi đã thay đổi vùng chứa của mình thành StructureMap.

Cảm ơn các bạn vì sự giúp đỡ của bạn! Thực sự đánh giá cao nó!

0

Di chuyển khởi tạo đó ra khỏi hàm tạo.

7

Như mọi khi, khi bạn có một phần phụ thuộc vào giá trị thời gian chạy, the solution is an Abstract Factory.

Something như thế này nên làm việc:

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

Bây giờ tiêm một IExchangeRateFactory vào người tiêu dùng của bạn thay vì ExchangeRate và sử dụng phương pháp GetExchangeRate để chuyển đổi các giá trị thời gian chạy tới một thể hiện ExchangeRate.

Rõ ràng bạn cũng sẽ cần cung cấp triển khai IExchangeRateFactory và định cấu hình NInject để ánh xạ giao diện đến triển khai của bạn.

+0

Hãy xem tôi có hiểu không. My OrderCalculator/ShippingCalculator phải nhận một đối tượng (IExchangeRateFactory) có khả năng xây dựng lớp ExchangeRate và gọi GetExchangeRate truyền tham số thời gian chạy, đúng không? Nếu có, thì tham số runTimeValue sẽ trở thành thứ mà OrderCalculator/ShippingCalculator nên quan tâm và tôi muốn điều đó không vui vẻ. – tucaz

+0

Nếu * none * trong số đó phải xử lý giá trị thời gian chạy, thì nó sẽ đến từ đâu? –

+0

Tôi hiểu những gì bạn đang nói, nhưng nếu tôi làm như vậy thì một cái gì đó (runTimeValue) mà chỉ là một phụ thuộc của ExchangeRate cũng sẽ trở thành một phụ thuộc vào bất kỳ lớp nào khác sử dụng nó. Tôi đang tìm một cách để vượt qua runTimeValue này để DI Container và để cho nó chăm sóc của việc tạo ra các đối tượng. – tucaz

1

Bạn có thể tìm thấy tiêm factory delegates hoặc providers để hữu ích. Cả hai đều có nhiều ý nghĩa của câu trả lời của Mark (+ 1d).

0

Updated dựa trên mã:

//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);  
} 

Thông báo như thế nào phương pháp này chỉ muốn runtimeValue để nó có thể vượt qua nó để cái gì khác? Điều này xảy ra bởi vì xây dựng đối tượng và trách nhiệm thời gian chạy được trộn lẫn. Tôi nghĩ bạn nên yêu cầu một IOrderCalculator trong hàm tạo cho phương thức này.

Vì vậy, phương pháp này chỉ trở thành:

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

Bây giờ, khi bạn xây dựng IOrderCalculator của bạn, bạn phải vượt qua runtimeValue để xây dựng nó. Đó là một chút khó khăn để trả lời khi chúng ta không biết runtimeValue là gì hoặc nó đến từ đâu.

+0

Nó hoạt động, nhưng sau đó tham số này cũng sẽ trở thành một phụ thuộc vào bất cứ ai đang sử dụng ExchangeRate khi nó không đúng sự thật. – tucaz

+0

runTimeValue là tham số INT có ID quốc gia/tiểu bang/thành phố được sử dụng để xác định thuế suất được sử dụng và nó đến từ cuộc gọi phương thức WCF. Đó là lý do tại sao nó chỉ có sẵn trong thời gian chạy và cũng là lý do tại sao tôi không thể sử dụng nó trong việc tạo ra dịch vụ WCF để xây dựng IOrderCalculator. Nó chỉ có sẵn sau khi WCF được xây dựng. – tucaz

+0

Trong trường hợp đó, câu trả lời của Mark Seemanns là đúng. –

Các vấn đề liên quan