通过购物车折扣功能了解规则引擎的概念

发布:2024-09-30 11:14 阅读:97 点赞:0

在本文中,我们将深入探讨规则引擎的概念,并通过 NRules(.NET 包)实现其功能。为便于理解,我们将创建一个新的 .NET 8 桌面应用程序,演示基于用户会员状态(普通/银卡/金卡/VIP)的购物车折扣功能。

一、规则引擎简介

功能目的

规则引擎是一种软件系统,能够在运行时执行一个或多个业务规则。这些规则可能来源于法律法规、公司政策或其他来源。规则引擎可以被视为一种复杂的 if/then 语句解释器,其主要优点是业务规则可以以非程序员易于理解的方式编写,并且这些规则可以在不更改基础应用代码的情况下进行修改。

NRules - 介绍

NRules 是一个开源的 .NET 规则引擎,支持将业务规则与系统逻辑分离。它允许使用 C# 编写规则,通过内部 DSL 表达规则条件和动作。NRules 高度可扩展,可以与任何 .NET 应用程序集成,并支持动态规则编译。

二、使用 NRules 实现购物车折扣逻辑

功能目的

在本示例中,我们将创建一个简单的 C# 控制台应用程序,使用 NRules 根据用户的会员类型(普通、银卡、金卡、VIP)应用不同的折扣百分比。

解决方案

步骤 1: 设置项目

首先,在 Visual Studio 中创建一个新的控制台应用程序或使用 .NET CLI。然后,通过 NuGet 添加 NRules 和 NRules.Runtime 包。

dotnet add package NRules
dotnet add package NRules.Runtime

步骤 2: 定义域模型

创建客户和订单类。

public class Customer
{
    public string MembershipType { getset; } // 会员类型
}

public class Order
{
    public Customer Customer { getset; } // 订单所属客户
    public decimal TotalAmount { getset; } // 订单总金额
    public decimal DiscountedAmount { getset; } // 折后金额
}

步骤 3: 定义规则

创建一个 MembershipDiscountRule 类来处理折扣规则。为简化起见,我们将所有规则整合到一个类中。

using RuleEngine_ShoppingCartDiscount.Models; // 引入模型命名空间
using NRules.Fluent.Dsl; // 引入 NRules Fluent DSL
using System;

namespace RuleEngine_ShoppingCartDiscount
{
    public class MembershipDiscountRule : Rule
    {
        public override void Define()
        {
            Order order = null;

            When()
                .Match<Order>(() => order,
                              o => o.Customer != null// 确保客户不为空
                              o => o.DiscountedAmount == 0); // 确保未应用折扣

            Then()
                .Do(ctx => ApplyDiscount(order)) // 应用折扣
                .Do(ctx => ctx.Update(order)); // 更新订单
        }

        private void ApplyDiscount(Order order)
        {
            var discount = order.Customer.MembershipType switch
            {
                "Normal" => 0.90m, // 10% 折扣
                "Silver" => 0.80m, // 20% 折扣
                "Gold" => 0.75m, // 25% 折扣
                "VIP" => 0.70m, // 30% 折扣
                _ => 1.00// 无折扣
            };

            order.DiscountedAmount = order.TotalAmount * discount; // 计算折后金额
            Console.WriteLine($"Applied {((1 - discount) * 100)}% discount for {order.Customer.MembershipType} member. Total now: {order.DiscountedAmount}");
        }
    }
}

步骤 4: 配置并运行规则引擎

Main 方法中,设置规则库、编译规则、创建会话,并创建客户列表(普通、银卡、金卡、VIP)。

// 加载规则
using NRules;
using NRules.Fluent;
using RuleEngine_ShoppingCartDiscount;
using RuleEngine_ShoppingCartDiscount.Models;

var repository = new RuleRepository();
repository.Load(x => x.From(typeof(MembershipDiscountRule).Assembly)); // 从程序集加载规则

// 编译规则
var factory = repository.Compile();

// 创建会话
var session = factory.CreateSession();

var customers = new List<Customer>
{
    new Customer { MembershipType = "Normal" },
    new Customer { MembershipType = "Silver" },
    new Customer { MembershipType = "Gold" },
    new Customer { MembershipType = "VIP" }
};

// 创建客户和订单
foreach (var customer in customers)
{
    var order = new Order { Customer = customer, TotalAmount = 100 }; // 初始化订单

    // 将事实插入规则引擎的内存
    session.Insert(order);

    // 启动匹配/解析/执行周期
    session.Fire();

    Console.WriteLine($"Final amount to pay: {order.DiscountedAmount}\n"); // 输出最终支付金额
}

Console.ReadLine();

步骤 5: 测试应用程序

运行控制台应用程序,它将打印出所有基于会员资格的折扣价格。

代码解释

  • 规则定义: 单个规则通过使用 switch 表达式处理所有会员类型,确定基于会员类型的折扣率。
  • 规则引擎设置: 规则被加载并编译,同时创建会话,在其中将订单作为事实插入。
  • 执行: session.Fire() 方法触发规则引擎,评估插入的事实与已编译规则,并应用相应的折扣。

三、结论

在 .NET 应用程序中利用 NRules 这样的规则引擎提供了一种强大的方法,将业务逻辑与应用程序代码分离。这种分离增强了可维护性、灵活性和可扩展性,使得在不对核心应用进行大量修改的情况下更容易适应变化的业务需求。有关 NRules 文档和架构流程的更多详细信息,请访问 NRules 官方文档页面。