Strategy Extension

The last few articles I’ve posted have been about my Builder library. That library is a great tool for simplifying the process of configuring and creating complex objects. But, even though I extended the classic GOF Builder pattern to include Setups and Providers, there is still room for improvement.

The problem I see is, the Provider classes themselves have the propensity to grow in complexity over time. After all, each Provider is tasked with housing at least part of the logic for constructing a Product. It seems clear that, as Products take on more features, the Providers that assemble those Products will also become busier.

That’s one of the reasons I try to keep my Provider classes simple by having them focus solely on passing out resources. My goal is to have no business logic at all in my Provider classes. I realize that’s almost exactly the opposite to what other companies do with their Provider classes, but, it seems to work for me.

The goal of “simple Providers” is great and all, but it means that I have to devise some other place for the business logic to go. Luckily, smarter people than I long ago devised other design patterns to deal with just this sort of thing. In fact, the Strategy pattern immediately springs to mind as a great solution.

In a nutshell, the Strategy pattern is used to select (or swap out) an algorithm at runtime. The pattern is usually implemented by defining an interface with a common signature and then implementing that interface in a bunch of classes.

Joining the Strategy pattern to the Builder I already have seems like a good fit. The question is, can I do it in any kind of reusable fashion? I think I can certainly come up with a base Strategy interface, something like this probably works:

I won’t win any design awards for that interface but it’s a decent start. Pairing a base class with the interface promises to be a little more interesting because it’s a great place to make an association between the Product, Provider, Setup, and implicitly, the Strategy. Something like this seems to be a good start:

This is great because now any concrete Strategy classes we create will automatically have a reference to the Product they belong to, as well as the Provider they came from and the Setup they were configured by.

But wait! What are the IStrategyProvider and IStrategySetup intefaces and why do we need them? First let’s look at those two interfaces:

Again, no design awards here, but, we have taken a step, together with the StrategyBase class, towards making a type-safe association between Strategy specific Providers and Setups. How important is that type safety, really? I’ve no idea right now, but later on, as we add any kind of Strategy specific behaviour to any of these types, it might become a bigger deal. In any event, it doesn’t really cost us much of anything and at least it gives us a common hook to hang Strategy specific Providers and Setups from, in the future.

So, there are interfaces for the Provider and Setup, that means we’ll need corresponding base classes as well. Let’s look at those next:

No real surprises there. The two classes don’t have any methods or properties because their associated interfaces also don’t have any methods or properties – yet. Bear in mind, that might change down the road. For instance, I’m mulling the notion of giving the IStrategy interface a Name property, which might make it easier to identify one instance of a Strategy from another. Anyway, that’s still just something I’m thinking about.

So how would we use these base classes? I’ll contrive a quick example:

Here is an application that a bartender can use to ensure that they never serve an adult beverage to an underage person:

In the main method we loop and ask for a patrons age, then we make a determination about whether or not to serve them a beer. To do that, we create a builder, add a setup to that builder, configure the setup with the patron’s age, then make the decision and show the results.

To be fair, it’s probably simpler and more efficient to create single product and pass the age into the CanDrinkBeer method, as a parameter. I passed the age through the Setup in order to get all the pieces involved in the demonstration.

So, for the code above to work, we first need to have a MyBuilder class. Let’s see what that looks like:

The MyBuilder class wants to create a Product – in this case an instance of the MyProduct class. Let’s see what the MyProduct class looks like:

The MyProduct class uses it’s collection of Providers to create a Strategy for making the decision about whether or not our prosective customer can drink beer. This way, the provider stays nice and lean and we can swap out our Strategy on a State by State basis, to deal with varying liquor laws. The MyStrategy class holds the actual logic for making the decision. Let’s go look at that class next:

The Strategy uses the person’s age to make the Yes / No decision. That age, for this example, is stored in the Setup. The strongly typed association between the Strategy and the Setup, thanks to the StrategyBase base class, means that the Strategy has quick access to the entire configuration for the Strategy.

Here’s the code for the MyProvider class:

Nice, simple provider. Just the way we like it. All the actual logic is encapsulated in the MyStrategy class, where it should be.

Here’s a look at the MySetup class:

This is a pretty typical Setup class with Set… methods for putting values into setup properties, and Get… method for returning those values back again. Keep in mind that a Setup may (and should) contain properties for everything a Provider may need at runtime. In our case, for this demonstration, that’s just an age.

Let’s look at the code we used to inject the MySetup into the MyBuilder instance, in the main method of the example:

There’s actually nothing saying you have to add setups to builders this way, but, this approach does make the process cleaner and allows you to restrict what sorts of Builder classes your Setup class can work with simply by changing the type of the Builder parameter. For instance, if the method used IBuilder for the parameter type then the MyProvider type could be injected into any Builder type, not just into a MyBuilder type.

So to summarize, creating a Strategy type, along with a StrategyProvider and StrategySetup type, help us extend the Builder library and easily dispense Strategy objects from Providers. Those Strategy types are integrated with the Builder and easy to work with. By creating a StrategyBase class we were able to create a typesafe association between a Strategy and it’s Product, Provider and Setup.

The code for this article is part of my NUGET package CG.Builder.Strategy, which can be downloaded for free at https://github.com/CodeGator/CG.Builder.Strategy

The source code for the CG.Builder.Strategy package lives on Github and can be obtained for free at https://www.nuget.org/packages/CG.Builder.Strategy/

That’s about it. I hope this article was helpful. Have fun with the code!