你的位置:首页 > ASP.net教程

[ASP.net教程]Asp.net 面向接口可扩展框架之业务规则引擎扩展模块


随着面向接口可扩展框架的继续开发,有些功能开发出现了"瓶颈",有太多的东西要写死才好做。但写死的代码扩展性是非常的不好,迷茫中寻找出入...

进而想到我以前开发的好几个项目,都已有一定的可配置能力,想想把这个地方抽象提取出来,进而想到"业务规则引擎",网上找了几个都不太入"眼",就抽时间再造个"轮子"

业务规则引擎在很多成熟的工作流引擎中都有相应的模块,是工作流的核心之一。但是除了工作流很多业务都需要业务规则引擎,所以它非常有必要独立作为一个模块。

在现实中很多项目开发都需要一些定制化的分支需求,为了这些需要把项目搞的鸡飞狗跳。使用业务规则引擎来做逻辑路由、参数“矫正”、拦截等,说是如虎添翼应该不为过。


 这里使用社区发文章来做个例子

1、先看文章相关模型

A:ArticleRepository是文章数据仓储,实际是把文章存放在内容的List中

B:User是文章作者,Article就是文章了,ArticlePublish是DTO,包含文章和作者的信息

2、文章有不同的分类

    ArticleRepository TopArticles = new ArticleRepository { Name = "置顶" };    ArticleRepository PerfectArticles = new ArticleRepository { Name = "精华" };    ArticleRepository NetArticles = new ArticleRepository { Name = ".Net" };    ArticleRepository OtherArticles = new ArticleRepository { Name = "其他" };

A:其中分为.net文章和其他文章,另外还有一个推送分类置顶和精华

B:文章现在分为.net文章和其他文章两个分类,以后很难说不用增加Java、PHP等其他分类,所以这个地方需要可扩展

C:不是每个人发的文章都置顶和精华,要不就没法越快的玩耍了

3、可以按授权进行推送

先看授权相关建模

这里都是用内存对象来模拟存储,我的数据模块(抽象)

A:Role是角色,角色有个权重的字段(Sort),Sort值越大权限越大

(有人说角色不应该是平等的吗?通过绑定资源来控制权限?我想问国家主席和你们村主任能平等吗?角色特权和资源绑定等手段应该综合来用。再次我们是演示业务规则引擎的,不是专门讨论权限系统的,先打住)

B:RolePermission用于授权(Grant)和获取权限(判断权限),维护者一个用户和权限的关联关系

  public class RolePermission : IEntityAccess<User, Role>, IComparer<Role>  {    private Dictionary<User, Role> _permission = new Dictionary<User, Role>();    public bool Grant(User user, Role role)    {      Role role0 = Get(user);      if (role0 != null && role0.Sort >= role.Sort)        return true;      _permission[user] = role;      return true;    }    public Role Get(User user)    {      Role role = null;      _permission.TryGetValue(user, out role);      return role;    }    int IComparer<Role>.Compare(Role x, Role y)    {      return Comparer<Role>.Default.Compare(x, y);    }  }

RolePermission

4、继续场景设置

    Role manager = new Role { Id = 1, Name = "管理员", Sort = 9999 };    Role expert = new Role { Id = 2, Name = "专家", Sort = 999 };

    User user1 = new User { Id = 1, Name = "张三", Year = 3 };    User user2 = new User { Id = 2, Name = "李四", Year = 10 };    User user3 = new User { Id = 3, Name = "王二", Year = 0 };

5、现在可以开始发文章了 

      RolePermission permission = new RolePermission();      ConfigRole(permission);      ArticlePublish post1 = new ArticlePublish(user1, new Article { Content = ".Net" });      ArticlePublish post2 = new ArticlePublish(user2, new Article { Content = "Java" });      ArticlePublish post3 = new ArticlePublish(user3, new Article { Content = "Php" });      Engine<ArticlePublish, int> engine = new Engine<ArticlePublish, int>();      ConfigCategory(engine);      Post(engine, post1, post2, post3);      Show(TopArticles, PerfectArticles, NetArticles, OtherArticles);

    private void ConfigRole(RolePermission permission)    {      permission.Grant(user3, expert);    }

授权代码
    private static void Post(Engine<ArticlePublish, int> engine, params ArticlePublish[] articles)    {      foreach (var item in articles)      {        int id = 0;        if (engine.Run(item, ref id))          Console.WriteLine(string.Concat("文章处理成功,Id=", id.ToString()));      }    }

发表文章代码
    private static void Show(params ArticleRepository[] repositorys)    {      foreach (var repository in repositorys)      {        Console.WriteLine(new string('-', 80));        List<Article> list = repository.ListAll();        if (list.Count < 1)        {          Console.WriteLine(string.Concat(repository.Name, " 无"));          continue;        }        Console.WriteLine(repository.Name);        foreach (var item in list)        {          Console.WriteLine(string.Concat("Article{Id=", item.Id, ",Content=", item.Content, "}"));        }        Console.WriteLine(new string('-', 80));      }    }

显示所有文章代码
文章处理成功,Id=1文章处理成功,Id=2文章处理成功,Id=3--------------------------------------------------------------------------------置顶 无--------------------------------------------------------------------------------精华 无--------------------------------------------------------------------------------.NetArticle{Id=1,Content=.Net}----------------------------------------------------------------------------------------------------------------------------------------------------------------其他Article{Id=2,Content=Java}Article{Id=3,Content=Php}--------------------------------------------------------------------------------

三篇文章发表成功,一篇.net,两篇其他,效果非常不错

先等等,Engine<ArticlePublish, int>是什么鬼,要发文章不应该是ArticleRepository吗?

Engine就是大名鼎鼎的业务规则引擎了,ArticleRepository发表文章不假,但是都是由Engine决定发不发,用谁发,这些就是业务规则,

(ArticleRepository就是值负责存储和读取,职责非常单一)

6、把业务规则定义看一下

    private void ConfigCategory(Engine<ArticlePublish, int> engine)    {      engine.When(post => post.Article.Content.Contains(".Net")).Then(post => NetArticles.Add(post.Article));      engine.Then(post => OtherArticles.Add(post.Article));    }

非常简单,如果文章包含.net关键字,使用NetArticles存储,否则使用OtherArticles存储(分表就是这么简单!!!)

 7、继续推送的例子

      Engine<ArticlePublish, int> pushEngine = new Engine<ArticlePublish, int>();      ConfigPush(permission, pushEngine);      ConfigYear(pushEngine);      Post(pushEngine, post1, post2, post3);      Show(TopArticles, PerfectArticles, NetArticles, OtherArticles);

文章处理成功,Id=2文章处理成功,Id=3--------------------------------------------------------------------------------置顶Article{Id=3,Content=Php}----------------------------------------------------------------------------------------------------------------------------------------------------------------精华Article{Id=2,Content=Java}----------------------------------------------------------------------------------------------------------------------------------------------------------------.NetArticle{Id=1,Content=.Net}----------------------------------------------------------------------------------------------------------------------------------------------------------------其他Article{Id=2,Content=Java}Article{Id=3,Content=Php}--------------------------------------------------------------------------------

 这次在置顶和精华都各有一篇了

8、我们看一下推送规则是怎么定义的

    private void ConfigPush(RolePermission permission, Engine<ArticlePublish, int> engine)    {      int topNum = 0;      int topLimit = 1;      engine.When(post => topNum < topLimit && Comparer<Role>.Default.Compare(permission.Get(post.User), expert) >= 0).Then(post => { topNum++; return TopArticles.Add(post.Article); });      engine.When(post => Comparer<Role>.Default.Compare(permission.Get(post.User), expert) >= 0).Then(post => PerfectArticles.Add(post.Article));    }

    private void ConfigYear(Engine<ArticlePublish, int> engine)    {      engine.When(post => post.User.Year >= 8).Then(post => PerfectArticles.Add(post.Article));    }

就是这么简单,老板再也不用担心我不会写业务规则了

 

 以上都是使用Fluent代码来做业务规则引擎的,以后我还需要做使用配置做动态业务规则的例子,以便在容器配置文件中使用