4

我試圖在使用Windsor容器時實現策略模式。以下是我有:基於條件的容器解析

public class OrderProcessor { 
... 
    public OrderProcessor(ITaxStrategy strategy) {} 

    public void Process(Order order) 
    { 
     order.Tax = strategy.CalcTax(order); 
    } 
} 

的問題是,我該如何配置我的容器(其它容器的例子歡迎)有本質上,選擇適當的依賴的標準。因此,如果我註冊以下內容

public class USTaxStrategy : ITaxStrategy { ... } 
public class CanadaTaxStrateg : ITaxStrategy { ... } 

如何使用Order.Destination(地址)作爲注入依賴項的標準?

+0

簡短的回答:寫一個TaxStrategyFactory – 2009-10-27 15:24:39

+0

嗯 - 你會如何在施工期間向工廠提供參數? – 2009-10-28 02:07:39

回答

6

以下是一些選項,請選擇您最喜歡的選項。我通常使用第一個,這是最簡單的。

[TestFixture] 
public class TaxStrategyTests { 
    [Test] 
    public void InjectWithFactory() { 
     var container = new WindsorContainer(); 
     container.AddComponent<USTaxStrategy>(); 
     container.AddComponent<CanadaTaxStrategy>(); 
     container.AddComponent<OrderProcessor>(); 
     container.AddComponent<ITaxStrategyFactory, TaxStrategyFactory>(); 
     var order = new Order {Country = "US"}; 
     container.Resolve<OrderProcessor>().Process(order); 
     Assert.AreEqual(10, order.Tax); 
    } 

    [Test] 
    public void InjectWithFactoryFromDictionary() { 
     var container = new WindsorContainer(); 
     container.AddFacility<FactorySupportFacility>(); 
     container.AddComponent<USTaxStrategy>(); 
     container.AddComponent<CanadaTaxStrategy>(); 
     container.AddComponent<OrderProcessor>(); 
     container.Register(Component.For<ITaxStrategyFactory>() 
           .UsingFactoryMethod(kernel => new TaxStrategyFactory2(new Dictionary<string, ITaxStrategy> { 
            {"US", kernel.Resolve<USTaxStrategy>()}, 
            {"CA", kernel.Resolve<CanadaTaxStrategy>()}, 
           }))); 
     var order = new Order { Country = "US" }; 
     container.Resolve<OrderProcessor>().Process(order); 
     Assert.AreEqual(10, order.Tax); 
    } 

    [Test] 
    public void InjectWithProxy() { 
     var container = new WindsorContainer(); 
     container.AddComponent<USTaxStrategy>(); 
     container.AddComponent<CanadaTaxStrategy>(); 
     container.AddComponent<OrderProcessorInterceptor>(); 
     container.AddComponent<ITaxStrategyFactory, TaxStrategyFactory>(); 
     container.Register(Component.For<OrderProcessor2>() 
           .LifeStyle.Transient 
           .Interceptors(InterceptorReference.ForType<OrderProcessorInterceptor>()).First); 
     var order = new Order {Country = "CA"}; 
     container.Resolve<OrderProcessor2>().Process(order); 
     Assert.AreEqual(5, order.Tax); 
    } 

    public class OrderProcessorInterceptor : IInterceptor { 
     private readonly ITaxStrategyFactory strategyFactory; 

     public OrderProcessorInterceptor(ITaxStrategyFactory strategyFactory) { 
      this.strategyFactory = strategyFactory; 
     } 

     public void Intercept(IInvocation invocation) { 
      if (invocation.MethodInvocationTarget.Name == "Process") { 
       var processor = (OrderProcessor2) invocation.InvocationTarget; 
       var order = (Order) invocation.Arguments[0]; 
       processor.Strategy = strategyFactory.Create(order); 
      } 
      invocation.Proceed(); 
     } 
    } 

    public interface IOrderProcessor { 
     void Process(Order order); 
    } 

    public class OrderProcessor2 : IOrderProcessor { 
     public ITaxStrategy Strategy { get; set; } 

     public virtual void Process(Order order) { 
      order.Tax = Strategy.CalcTax(order); 
     } 
    } 

    public class OrderProcessor : IOrderProcessor { 
     private readonly ITaxStrategyFactory strategyFactory; 

     public OrderProcessor(ITaxStrategyFactory strategyFactory) { 
      this.strategyFactory = strategyFactory; 
     } 

     public void Process(Order order) { 
      var strategy = strategyFactory.Create(order); 
      order.Tax = strategy.CalcTax(order); 
     } 
    } 

    public interface ITaxStrategyFactory { 
     ITaxStrategy Create(Order o); 
    } 

    public class TaxStrategyFactory : ITaxStrategyFactory { 
     private readonly IKernel kernel; 

     public TaxStrategyFactory(IKernel kernel) { 
      this.kernel = kernel; 
     } 

     public ITaxStrategy Create(Order o) { 
      if (o.Country == "US") 
       return kernel.Resolve<USTaxStrategy>(); 
      return kernel.Resolve<CanadaTaxStrategy>(); 
     } 
    } 

    public class TaxStrategyFactory2: ITaxStrategyFactory { 
     private readonly IDictionary<string, ITaxStrategy> strategies; 

     public TaxStrategyFactory2(IDictionary<string, ITaxStrategy> strategies) { 
      this.strategies = strategies; 
     } 

     public ITaxStrategy Create(Order o) { 
      return strategies[o.Country]; 
     } 
    } 

    public interface ITaxStrategy { 
     decimal CalcTax(Order order); 
    } 

    public class USTaxStrategy : ITaxStrategy { 
     public decimal CalcTax(Order order) { 
      return 10; 
     } 
    } 

    public class CanadaTaxStrategy : ITaxStrategy { 
     public decimal CalcTax(Order order) { 
      return 5; 
     } 
    } 

    public class Order { 
     public string Country { get; set; } 
     public decimal Tax { get; set; } 
    } 
} 
+0

夠簡單,謝謝Mauricio。我希望在溫莎有一些標準設施可以(有助於)選擇,並且如果沒有工廠中間人,我可以依賴ITaxStrategy。 – 2009-10-30 11:28:37

+0

這是不可能的,因爲容器必須知道特定的Order實例,因此是代理解決方案。另一種選擇是將訂單轉移到某種背景下,但這會使事情變得更加複雜。 – 2009-10-30 12:25:10

+3

對於那些未來的人來說,我將一個帖子和示例VS 2K8解決方案放在一起。 http://blog.cromwellhaus.com/index.php/2009/10/strategy-pattern-with-castle-windsor/ – 2009-11-02 20:41:25