In the previous post, I covered the basics of expression trees, including their structure and how to create them in .NET. Now, let’s dive into a real-world example: building a simple Business Rule Engine (BRE) using expression trees. This engine will apply discount rules based on certain conditions.
Scenario: Discount Calculation
Imagine you are working on an e-commerce platform, and you need to implement a business rule engine (BRE) system, and one of its features is to calculate discounts based on various business rules. These rules might include conditions like:
- If the customer is a premium member AND the order amount is greater than $100, apply a 10% discount.
- If the order contains more than 5 items OR the order amount is greater than $200, apply a 5% discount.
Building the Business Rule Engine
We’ll build a modular Business Rule Engine that evaluates these conditions dynamically using expression trees. (using expressions, we can make cleaner, more maintainable, and performant code)
Step 1: Define the Data Model
First, let’s define our data model for orders and customers.
public class Order
{
public decimal Amount { get; set; }
public int ItemCount { get; set; }
public bool IsPremiumMember { get; set; }
}
Step 2: Define the Rule Structure
Next, we’ll define the structure for our discount rules.
public class DiscountRule
{
public Expression<Func<Order, bool>> Condition { get; set; }
public decimal DiscountPercentage { get; set; }
}
Step 3: Create the Rule Engine
We’ll create a class to manage and evaluate these rules.
public class RuleEngine
{
private readonly List<DiscountRule> _rules = new List<DiscountRule>();
public void AddRule(DiscountRule rule)
{
_rules.Add(rule);
}
public decimal CalculateDiscount(Order order)
{
foreach (var rule in _rules)
{
var compiledCondition = rule.Condition.Compile();
if (compiledCondition(order))
{
return rule.DiscountPercentage;
}
}
return 0;
}
}
Step 4: Define the Discount Rules
Now let’s define our discount rules using expression trees.
using System;
using System.Linq.Expressions;
class Program
{
static void Main()
{
var ruleEngine = new RuleEngine();
// Rule 1: If the customer is a premium member AND the order amount is greater than $100, apply a 10% discount.
var rule1 = new DiscountRule
{
Condition = order => order.IsPremiumMember && order.Amount > 100,
DiscountPercentage = 10
};
// Rule 2: If the order contains more than 5 items OR the order amount is greater than $200, apply a 5% discount.
var rule2 = new DiscountRule
{
Condition = order => order.ItemCount > 5 || order.Amount > 200,
DiscountPercentage = 5
};
ruleEngine.AddRule(rule1);
ruleEngine.AddRule(rule2);
// Example order
var order = new Order
{
Amount = 150,
ItemCount = 3,
IsPremiumMember = true
};
decimal discount = ruleEngine.CalculateDiscount(order);
Console.WriteLine($"Discount: {discount}%"); // Output: Discount: 10%
}
}
Benefits of Using Expression Trees
- Flexibility: Easily define and modify business rules without changing the core logic.
- Dynamic Evaluation: Compile and evaluate conditions at runtime.
- Modularity: Add or remove rules as needed without affecting other parts of the system.
- Performance: A compiled code can be run faster
Conclusion
By leveraging expression trees, we can build a flexible and modular Business Rule Engine that dynamically evaluates complex conditions. This approach not only simplifies the implementation of business logic but also enhances maintainability and scalability.
Stay tuned!