专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

抽取非基本验证到规则文件 - A2D规则引擎

基本验证与业务验证,基本验证就是始终保持不变的验证规则,可以通过如下硬编码实现:

public class Order
    {
        [Required]
        [Range(typeof(decimal), "1", "10000")]
        public decimal Price { get; set; }

        [Required]
        [StringLength(30)]
        public string Customer { get; set; }

        [Required(AllowEmptyStrings=true)]
        [StringLength(50)]
        public string StoreID { get; set; }
    }

然后在用如下代码validate, 把错误放到List中:

private bool ValidateBasicRule(Order order)
        {
            List<KeyValuePair<string, string>> errors = order.IsValid();
            if (errors.Count > 0)
            {
                this.AddRange(errors);
                return false;
            }

            return true;
        }

public static class DataAnnotationHelper
    {
        public static List<KeyValuePair<string, string>> IsValid<T>(this T o)
        {
            List<KeyValuePair<string, string>> errors = new List<KeyValuePair<string, string>>();

            var descriptor = GetTypeDescriptor(typeof(T));

            foreach (PropertyDescriptor propertyDescriptor in descriptor.GetProperties())
            {
                foreach (var validationAttribute in propertyDescriptor.Attributes.OfType<ValidationAttribute>())
                {
                    if (!validationAttribute.IsValid(propertyDescriptor.GetValue(o)))
                    {
                        errors.Add(new KeyValuePair<string, string>(propertyDescriptor.Name, validationAttribute.FormatErrorMessage(propertyDescriptor.Name)));
                    }
                }
            }
            return errors;
        }
        private static ICustomTypeDescriptor GetTypeDescriptor(Type type)
        {
            return new AssociatedMetadataTypeTypeDescriptionProvider(type).GetTypeDescriptor(type);
        }
    }

然后说说业务规则的易变

SaaS程序,或者业务规则极其易变时,就要采用其他方法来做了,不可能每个公司都用设计模式分开写(虽然也行,但是不方便,公司业务规则多了后,对这些规则代码的管理就是很高的成本,而且要developer来负责)。所以要用规则文件来分开规则的编写,好处:

1、 把修改的职责交给别人,比如项目经理、项目实施人员
2、 代码不需要重新编译就能实现业务规则的修改

我们来解决下这个易变问题,假设有2公司:A和B。

A公司验证规则:

1、 基本验证(就是Order类的验证规则的硬编码)
2、 自定义验证规则:当前Order的下单网址必须来自于这几个url,如:tech.souyunku.com、www.cnblogs1.com、www.cnblogs2.com

B公司验证规则:

1、 基本验证(同上)
2、 自定义验证规则:无

如果用A2D规则引擎来解决的话,需要怎么做呢?

第一步当然是编写规则文件,A公司的规则文件:

declare
    allowStores=["tech.souyunku.com", "www.cnblogs1.com", "www.cnblogs2.com"]
end declare
rule "test"
    when
        !_.contains(allowStores, entity.StoreID)
    then
        errors.Add("StoreID", "StoreID value not right")
end rule

由于B公司没有自定义规则,因此不需要编写相应的规则文件

第二步,调整验证逻辑,如下:

public class OrderService : BrokenRulesHolder
    {
        public int PlaceOrder(Order order)
        {
            this.ClearBrokenRules();
            //进行基本规则验证
            if (!ValidateBasicRule(order))
                return -1;

            //进行针对不同公司的规则验证
            if (!ValidateCompanyRule(order))
                return -1;

            //其他操作,比如插入数据库

            return 100;
        }

        private bool ValidateCompanyRule(Order order)
        {
            BrokenRulesHolder tempBrokenRulesHolder = new BrokenRulesHolder();
            string rulePath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Rules", "OrderValidations", SessionContext.CompanyID + ".r");
            using (RuleEngine engine = new RuleEngine(false))  //false代表:如果规则文件不存在不会报错,而是忽略,默认为true
            {
                engine.BindRulePath(rulePath);  //将规则文件的全路径传入引擎

                engine.SetParameter("entity", order);
                engine.SetParameter("errors", tempBrokenRulesHolder);

                engine.Process();
            }
            if (tempBrokenRulesHolder.BrokenRules.Count > 0)
            {
                this.AddRange(tempBrokenRulesHolder.BrokenRules);
                return false;
            }
            return true;
        }

        private bool ValidateBasicRule(Order order)
        {
            List<KeyValuePair<string, string>> errors = order.IsValid();
            if (errors.Count > 0)
            {
                this.AddRange(errors);
                return false;
            }

            return true;
        }
    }

BrokenRule.cs代码:

public class BrokenRulesHolder
    {
        private List<KeyValuePair<string, string>> brokenRules = new List<KeyValuePair<string, string>>();
        public List<KeyValuePair<string, string>> BrokenRules
        {
            get
            {
                return this.brokenRules.AsReadOnly().ToList();
            }
        }
        public void Add(string key, string msg)
        {
            brokenRules.Add(new KeyValuePair<string, string>(key, msg));
        }
        public void AddRange(List<KeyValuePair<string, string>> rules)
        {
            brokenRules.AddRange(rules);
        }
        public void ClearBrokenRules()
        {
            brokenRules.Clear();
        }
    }

demo代码已经更新到A2D框架中了,这里就不upload运行图了。

A2D规则引擎已经内嵌了underscore 1.5.2,因此规则定义文件(.r文件)中可以写相应的underscore函数来简化写法。

规则文件说明:

declare
    allowStores1=["tech.souyunku.com", "www.cnblogs1.com", "www.cnblogs2.com"]
    allowStores2=["tech.souyunku.com", "www.cnblogs1.com", "www.cnblogs2.com"]
end declare
rule "rule 1"
    when
        !allowStores1.contains(entity.StoreID)
    then
        errors.Add("StoreID", "StoreID value not right")
end rule
rule "rule 2"
    when
        !allowStores2.contains(entity.StoreID)
    then
        errors.Add("StoreID", "StoreID value not right")
end rule

declare section:

1、 可以不写,但是最多只能存在1个这样的section
2、 每行可以有逗号,也可以没有逗号
3、 这个section的本意是:当前规则文件的变量全局定义、初始化工作
4、 开头为declare,小写
5、 结尾为end declare,小写

rule section:

1、 必须存在1到多个
2、 每行可以有逗号,也可以没有逗号
3、 开头为rule “一些描述”,小写
4、 结尾为end rule,小写
5、 如果存在3个rule时,最终会变成这样的js逻辑

    加载underscore的js代码

    加载declare section的js代码

    if(rule1 conditions)
    {
          执行rule1的then语句
    }
    else if(rule2 conditions)
    {
          执行rule2的then语句
    }
    else if(rule3 conditions)
    {
          执行rule3的then语句
    }

大家可以下载代码进行自己修改,比如可以插入自己编写的js代码来更加简化或者更加贴近项目的自定义方法、函数。

文章永久链接:https://tech.souyunku.com/38964

未经允许不得转载:搜云库技术团队 » 抽取非基本验证到规则文件 - A2D规则引擎

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们