Strategy Selector
One of the most powerful patterns for EasyDecisions is using it as a Dynamic Strategy Selector.
Instead of returning simple data types, you can return an Interface. This allows your business rules to decide which implementation of a strategy should be used at runtime, while your calling code remains completely decoupled from the specific implementations.
The Scenario: AI Provider Selector
Imagine you have an application that integrates with multiple AI providers (OpenAI, Google, Codex). You want to select the provider based on the user's preference, but if they are a Premium user, you want to automatically upgrade them to the "Max" mode of that provider.
1. Define the Strategy Interface
First, define the interface that all AI providers will implement.
public interface IAiApi
{
string Call(string prompt);
}
// Implementations
public class OpenAIService : IAiApi { ... }
public class OpenAI_MaxMode : IAiApi { ... }
public class GoogleAIService : IAiApi { ... }
public class GoogleAI_MaxMode : IAiApi { ... }
public class CodexService : IAiApi { ... }2. Define Input and Output
The output of our decision will contain the instance of IAiApi that should be used.
public record AiRequest(string PreferredVendor, bool IsPremium);
public class AiSelectionResult
{
// The engine will populate this interface with a concrete instance
public IAiApi aiApi { get; set; }
}3. Build the Decision Table
Now, create the decision class. The rules will assign concrete implementations to the aiApi property.
We use the HitPolicy.First to ensure that as soon as a matching rule is found, we stop evaluation.
public class AiStrategyDecision : Decision<AiRequest, AiSelectionResult>
{
public AiStrategyDecision()
{
HitPolicy = HitPolicy.First;
// OpenAI Rules
When(i => i.PreferredVendor == "OpenAI" && i.IsPremium)
.Then()
.Set(o => o.aiApi = new OpenAI_MaxMode());
When(i => i.PreferredVendor == "OpenAI" && !i.IsPremium)
.Then()
.Set(o => o.aiApi = new OpenAIService());
// Google Rules
When(i => i.PreferredVendor == "Google" && i.IsPremium)
.Then()
.Set(o => o.aiApi = new GoogleAI_MaxMode());
When(i => i.PreferredVendor == "Google" && !i.IsPremium)
.Then()
.Set(o => o.aiApi = new GoogleAIService());
// Codex Rules
When(i => i.PreferredVendor == "Codex")
.Then()
.Set(o => o.aiApi = new CodexService());
}
}4. Use the Result
The beauty of this approach is that the calling code doesn't care which model was selected. It just calls the interface method.
var request = new AiRequest("OpenAI", IsPremium: true);
// The engine selects the "OpenAI_MaxMode" based on the rules
var result = EasyDecision.Evaluate<AiStrategyDecision>(request);
// Execute the strategy polymorphically
var response = result.aiApi.Call("Write a poem about C#");Why use this?
- Decoupling: Your main application logic doesn't have
if/elseorswitchstatements to pick a strategy. - Extensibility: Adding a new AI provider (like Anthropic) only requires a new implementation of
IAiApiand a new row in your decision table. - Testability: You can easily mock
IAiApiand verify that the decision engine selects the correct mock based on inputs.