Strategy Pattern with Castle Windsor

One of the tangent patterns associated with isolation or Single Responsibility is the Strategy Pattern.  I use Castle Windsor as my IoC of choice and I had hoped there was some black magic built in to make the Strategy Pattern dead simple.  Turns out there is and there isn’t.

What is the Strategy Pattern

The strategy pattern is a way of isolating what would often be found in a case statement.  The bland example being calculating Sales tax on an Order.  Each state and/or country has its own tax calculation and rather than

   1: public void Process(Order order) {
   2:     switch(order.Country) {
   3:         case "USA":
   4:             order.Total = order.Subtotal * .07;
   5:             break;
   6:         case "Canada":
   7:             order.Total = order.Subtotal * .0985;
   8:             break;
   9:     }
  11:     // ...
  12: }

you should be breaking each calculation out into different ITaxStrategy implementations and consuming them like so:

   1: public void Process(Order order) {
   2:     var strategy = _taxStrategyFactory.GetStrategyForOrder(order);
   4:     var salesTax = strategy.CalculateSalesTax(order);
   6:     order.SalesTax = salesTax;
   7:     order.Total = order.SubTotal + order.SalesTax;
   8: }

The question remains, how to eliminate the conditional logic in TaxStrategyFactory determining which strategy is chosen.  The solution is to set up a convention for discovering the available strategies and delegating the criteria to the Strategy itself.


The concept here is that we don’t have to “hook up” any new Tax Strategy to our Processing mechanism, we just “publish” new ones in a known way and they are picked up simply based on their existence.  This is often referred to as Convention Over Configuration.  We accomplish this with Castle Windsor with the Fluent Registration API:

   1: container
   2:     .Register(AllTypes
   3:                   .FromAssembly(Assembly.GetExecutingAssembly())
   4:                   .Where(x => x.Name.EndsWith("Strategy"))
   5:                   .WithService.FirstInterface());

This will register all classes found in the executing assembly which have the suffix “Strategy” as implementing the ITaxStrategy interface.  The second half of convention based discovery is consuming the ITaxStrategy implementations.  We can want to get all of these into the TaxStrategyFactory via a constructor array dependency:

   1: public TaxStrategyFactory(params ITaxStrategy[] taxStrategies)
   2: {
   3:     _taxStrategies = taxStrategies;
   4: }

Unfortunately, Windsor doesn’t support arrays as dependencies by default.  Windsor has the concept of Resolvers (a strategy implementation itself) and we are going to have to tell it about the ArrayResolver which knows how to, err, resolve array dependencies:

   1: container
   2:     .Kernel.Resolver.AddSubResolver(new ArrayResolver(container.Kernel));

Cool, so put these all together in our registration code and we get:

   1: container
   2:     .Register(Component
   3:                   .For<IOrderProcessor>()
   4:                   .ImplementedBy<OrderProcessor>())
   5:     .Register(Component
   6:                   .For<ITaxStrategyFactory>()
   7:                   .ImplementedBy<TaxStrategyFactory>())
   8:     .Register(AllTypes
   9:                   .FromAssembly(Assembly.GetExecutingAssembly())
  10:                   .Where(x => x.Name.EndsWith("Strategy"))
  11:                   .WithService.FirstInterface());

At this point we can kick of the true discovery chain of events through:

   1: var processor = container.Resolve<IOrderProcessor>();
   3: processor.Process(order);

Delegating Criteria

So in OrderProcessor.Process we are asked the TaxStrategyFactory for the applicable ITaxStrategy implementation:

   1: var strategy = _taxStrategyFactory.GetStrategyForOrder(order);
   3: var salesTax = strategy.CalculateSalesTax(order);
   5: //...

  The question is, how did the factory determine which of the boundless implementations applies?  That’s the job of each ITaxStrategy itself.  Here’s the implementation of our factory:

   1: class TaxStrategyFactory : ITaxStrategyFactory
   2: {
   3:     private readonly ITaxStrategy[] _taxStrategies;
   5:     public TaxStrategyFactory(params ITaxStrategy[] taxStrategies)
   6:     {
   7:         _taxStrategies = taxStrategies;
   8:     }
  10:     public ITaxStrategy GetStrategyForOrder(Order order)
  11:     {
  12:         return _taxStrategies.FirstOrDefault(x => x.IsApplicable(order));
  13:     }
  14: }

Notice how the TaxStrategyFactory depends on all of the ITaxStrategy implementations.  It then uses the ITaxStrategy.IsApplicable(Order) method as criteria for a FirstOrDefault call.  Here’s an example TaxStrategy for any Order with country “USA”:

   1: public class USTaxStrategy : ITaxStrategy
   2:     {
   3:         private static readonly IDictionary<string, double> TaxRates = new Dictionary<string, double>()
   4:                                                                    {
   5:                                                                        {"OH", 7.0},
   6:                                                                        {"MI", 6.25},
   7:                                                                    };
   8:         public double CalculateSalesTax(Order order)
   9:         {
  10:             var rate = TaxRates[order.State];
  12:             return (order.SubTotal * (rate / 100));
  13:         }
  15:         public bool IsApplicable(Order order)
  16:         {
  17:             return order.Country == "USA";
  18:         }
  19:     }


You can download the sample project that goes along with this here.

Dog Food II Registration Open

Registration has opened for the 2nd Annual Dog Food conference in Columbus, OH.  SDS is excited to be a sponsor and presenter this year and I hope you have a chance to come by and see some of the topics everyone has planned.  I plan to be there as an observer both days and a speaker the second.  You really need to be someone to get the final session on the final day (a Friday non-the-less), but it’s a topic I’m passionate about: Scrum with Team Foundation Server.

For an agenda and registration information, the venerable Jeff Blankenburg has made available the official Dog Food Conference site.

A Reminder Of Our Values

Steve Gentile recently had a thinking out loud moment by posting the Agile Manifest as a reminder to himself of what he values.  It’s really important to constantly put these types of reminders in front of ourselves as we work in environments that don’t necessarily breed best practices.  The contractual obligations of the business world definitely don’t lend to “welcoming change.”  Often our focus on “getting paid” blinds us to the goal of “continuous delivery of valuable software.”

It is a test of our dedication that we continually reassess our values and attempt to embed them more deeply in our daily activities..

Size versus Duration

Scrum introduces the concept of Story Points which most teams immediately misunderstand or discard.  The most elegant wrong explanation I’ve heard for not using story points was:

“we never liked story points, because then we had to communicate and teach our customers a whole new currency.” 

Fortunately, this isn’t true.  Unforunately, the reason many find story points hard to implement is because we seem to have a hard time differentiating Size from Duration.  Add Effort to the equation and you have your own little math game.  In fact, you get the mathematics of Project Management.  Blasphemy!

Here is the anecdote I’ve been using for a while now and it seems to work at least in explaining the difference.  I have two puzzles, one with 25 pieces and one with 100 pieces.  Each puzzle has pieces roughly the same size and complexity in imagery.  That being said, the 100 piece puzzle is 4 times as difficult as the 25 piece puzzle.  If I put 1 hours worth of effort into each puzzle per week, the duration until completion of the large 100 piece puzzle should be approximately 4 times longer.  Ho long (duration) it takes me to complete the puzzle is a factor of the effort and size.  Size doesn’t change, effort can.

Story Points are a relative unit of measure for size.  If my only two tasks are the two puzzles, the smaller could well be 1 Story Point, while the larger would be 4 Story Points.  If we find that a third puzzle of 12 pieces is added to the task list, it could be 1 Story Point, the 25 piece puzzle becomes a 2 and the final 100 piece puzzle would become an 8 Story Point Task.

Registering WPF “Views” with Windsor Fluent API

I’ve had this nagging issue for some time now with WPF views that are registered for an interface.  The Views themselves are WPF UserControls:

namespace SomeApp.Views
    public partial class SearchView : UserControl, ISearchView
        public SearchView()

        private void InitializeComponent()
            throw new NotImplementedException();


I would love to have registered all views in one go by simply adding:

                       .Where(x => x.Name.EndsWith("View"))


Unfortunately, this registers my Views for System.Windows.Media.Composition.DUCE+IResource implementations which I really couldn’t care less about.  The interface I’m looking for is the “nearest” interface for lack of a better term.  Fortunately, Windsor lets us provide a delegate selector for the interface.  Here’s what I’m using now:

                       .Where(x => x.Name.EndsWith(suffix))
                       .WithService.Select((t, bt) =>
                                                   var serviceType = t
                                                       .Where(x => x.FullName.StartsWith("SomeApp"))

                                                   if (serviceType != null)
                                                       return new[] {serviceType};
                                                       return new[] {t};


Use Select versus FirstInterface allows us to provide back the Service type(s?) that this class is implementing.  The StartsWith is obviously fragile, but I’m green right now, so I’ll see you on the other side.