• A2D规则引擎


     A2D规则引擎

    写了个简单的规则引擎,普通情况够用了:

    比如2家公司有各自的利率计算规则,如下:

    在C#方面,没有写在C#的业务逻辑代码中,而是移到了外部规则文件中,如(ACompanyRatePolicy.r):

    复制代码
    rule "Level 1"
        when
            alreadyCostPrice >= 0
            alreadyCostPrice < 100
        then
            rate = 1
    end
    rule "Level 2"
        when
            alreadyCostPrice >= 100
            alreadyCostPrice < 300
        then
            rate = 0.8
    end
    rule "Level 3"
        when
            alreadyCostPrice >= 300
        then
            rate = 0.5
    end
    复制代码

    不同的公司调用不同的Policy定义文件来执行逻辑:

    核心调用代码:

    复制代码
    public class CustomerRateService
        {
            public static decimal CalculateRate(decimal costedAlready, decimal priceThisTime, string rulePolicy)
            {
                using (RuleEngine engine = new RuleEngine(System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Rules")))
                {
                    engine.BindRule("Rating", rulePolicy);   //此处的第一个参数"Rating"是规则组名称,对应的是物理文件夹,方便规则文件的管理和查看
    
                    engine.SetParameter("alreadyCostPrice", costedAlready);
                    engine.SetParameter("thisTimePrice", priceThisTime);
    
                    engine.Process();
    
                    return engine.GetDecimal("rate");
                }
            }
            
        }
    复制代码

    原理比较简单:

    1. 根据规则文件(.r文件)生成js代码
    2. 在C#中嵌入v8引擎执行这段js代码
    3. 获取结果

    Make Things Move -- Javascript html5版(一)文件目录结构和工具方法准备

     

      从这一篇开始,就来开始我们的make things move之旅吧

      在此之前,要知道ActionScript(AS)的语法和JS是不一样的,AS是相对于JS而言更好的支持了面向对象的特性,所以我们可以自己实现一些简单的工具类,让我们更快速的构建我们的工程。不过我们不用全部实现AS中的东西,我们只用实现最基本的类的构造,类的继承和其他一些实用的工具函数就好了。

      其实我还想说的是,我们还是要实现AS的Sprite类和stage,因为这两个东西是实现AS动画最基本的元素,html5 canvas提供的js api还是比较低级的,我们可以简单的封装一下实现AS的sprite 和stage,不过这两个东西还是等后续讲有关动画的原理再来细说吧。另外,其实现在已经有很多开源的HTML5游戏框架,可以直接使用,而且已经很成熟社区也好,比如现在很火的cocos2d-html5,我不是很赞成自己造轮子写一个,不过如果是出于学习目的还是可以一试的,因为这样也比较容易理解框架底层的东西,和提高你的JS水平。话题跑远了……

      文件目录结构

      推荐模仿linux的文件结构吧,随便在哪放你的工程

                     

    复制代码
       创建一个/mtm的文件夹,此文件夹的根目录下:
        |-- index.html
        |-- /css 
        |-- /js
             |-- /bin      此目录旋转最终的用于执行的js文件 
             |-- /lib      放置库工具
             |-- /etc      放置配置文件
             |-- /mtm      make things move 工程的主要例子的实现类    
    复制代码

         工具方法

      一在js/lib/目录下创建一个sys.js的文件

      然后实现我们的第一个构造类的工具方法:__class__。我写多了python,深受python类构造模式的影响(同样的我也不分号党,只有在写java或其他静态语言的时候),双下划线是表示系统内置属性或方法的意思,这只是我自己的习惯,读者可以根据自己的习惯来写,不过建议有一个好的规范,我的在JS里就不算是什么好的。读者也可自己实现一个可构造类并能实现继承的方法,我的实现如下:

    复制代码
    // 参数不定,最后一个参数必须是实现的方法的json,前面的都是要继承的类
    // opts中的__init__方法则为新类的构造函数
    // example: var NewClass = __class__(Class1, Class2, {__init__: function () {}, })

    this
    .__class__ = function (/*Class1, Class2,..., opts*/) { var args = Array.prototype.slice.call(arguments), opts if (typeof args[args.length - 1] === 'function') opts = {} else opts = args.pop() var clss = opts.__init__ || function () {}, name = opts.__name__ || __filename__(__file__()) //获取当前js文件的名称作为这个类的类名,也可在opts中定义__name__ for (var i = 0, parent; parent = args[i]; i++) __copy__(parent.prototype, clss.prototype) __copy__(opts, clss.prototype) clss.__name__ = clss.prototype.__name__ = name return clss }
    复制代码

      上面的方法中用到了几个新的工具方法:

          1. __file__       获取当前文件路径

      2. __filename__   获取指定文件路径的文件名(已去掉后缀)

      3. __copy__             简单的拷贝属性的方法

      这些方法都在sys.js实现:

    复制代码
    this.__copy__ = function (source, target) {
        for (var k in source)
            target[k] = source[k]
        return target
    }
    
    this.__file__ = function () {
        var e = document.getElementsByTagName('script')
        return e.length ? e[e.length - 1].src : ''
    }
    
    // 获取当前文件所在的目录
    this.__dirname__ = function (s) { var p = s.lastIndexOf('/') if (p === 0) return '/' if (p === -1) return '' return s.slice(0, p) }
    // 获取指定文件路径的文件名字(带后缀)
    this.__basename__ = function (s) { var res = s.match(//([^/]+.w+)$/i) return res ? res[1] : '' } this.__filename__ = function (s) { var str = __basename__(s) return str.length ? str.slice(0, str.lastIndexOf('.')) : str }
    复制代码

      最后还有一个__load__方法,属于一个文件加载器,没办法js"还“没有import我们自己来实现一个

    复制代码
    /**
    * @param files {Array} 要加载的js文件的路径数组
    * @param ok {Function} 加载完成后的回调
    * @example: __load__(['js/sys.js'], function () {console.log('load done!')})
    */
    this
    .__load__ = function () { var _loaded_path = {} var _loader = function (src, fnc) { if (_loaded_path[src]) return fnc() var s = document.createElement("script") s.onload = function () { _loaded_path[src] = 1 fnc() } s.onerror = function () { throw "Error loading: " + src } s.src = src document.body.appendChild(s) } return function (files, ok) { files = files.slice() if (files.length == 0) return ok && ok() _loader(files.shift(), function () { __load__(files, ok) }) } }()
    复制代码

      把上面的代码都放到js/lib/sys.js文件中,就基本完成我们的的工具准备了,我们来试试使用上面的方法,顺便熟悉我们的文件 结构,在 js/mtm/   文件夹下创建一个Test.js文件,在这里我们用我们的工具函数创建我们的第一个类:

    复制代码
    var Test = __class__({
    
        __init__: function () {
            this.sayMyName()
        },
    
        sayMyName: function () {
            alert("I am a Class, my name is " + this.__name__)
        }
    
    })
    复制代码

    再写一个继承类,和Test.js同目录下创建OtherTest.js(注意,我们的__class__方法是可以多重继续的,只是新类里没有可间接从自己类里调用父类的方法):

    复制代码
    var OtherTest = __class__(Test, {
    
        __init__: function () {
            // 手动调用父类的构造方法
            Test.call(this)
        },
    
        sayMyName: function () {
            // 手动调用父类的sayMyName方法
            Test.prototype.sayMyName.call(this)
            // 再弹出一个信息
            alert("All done!")
        }
    
    })
    复制代码

    类是写完了,但我们并没有引用,我们来部署一下我们测试环境:在js/etc/ 目录下创建一个mtm_module.js的文件,里面把我们js/mtm/文件里的js路径都写入一个mtm_module数组中:

    var mtm_module = [
        'js/mtm/Test.js',
    'js/mtm/OtherTest.js',

    ]

    以后都把mtm文件的路径往这个数组里加。在js/lib/目录下创建一个main.js的最终执行文件,然后主要就是在这个文件中加载其他js 执行测试代码:

    复制代码
    // 把js/mtm/里的测试类都加载进来
    __load__(mtm_module, function () {
    
        // 实例化一个Test类
        var test = new Test()
    
    })
    复制代码

    最后就是写index.html页面,把主要的sys.js,mtm_module.js, main.js用标签引入就OK了:

    复制代码
    <!doctype html>
    <html>
    <head>
      <title> Make things move </title>
    </head>
    
    <body>
    <script src='js/lib/sys.js'></script>
    <script src='js/etc/mtm_module.js'></script>
    <script src='js/bin/main.js'></script>
    </body>
    </html>
    复制代码

      到此,如果过程都没有任何问题,你可以打开index.html    然后就会弹出我们上面写的信息!如果你用的是mac 或 linux系统建议直接用命令行工具在该工程根目录输入`python -m SimpleHTTPServer 8000` 然后浏览器上打开localhost:8000就能看到效果了。写了这么多,可能篇幅有些长,下次写看来要控制一下 :p

     

     
     
     

    代码已经更新到A2D Framework了。

    大家拿去用吧。。。哈哈。

    自省推动进步,视野决定未来。
    心怀远大理想。
    为了家庭幸福而努力。
    A2D科技,服务社会。
    A2D Framework(Alpha)
    • 1. Cache System(本地缓存与分布式缓存共存、支持Memcache和Redis、支持贴标签形式(类似Spring 3.x的Cache形式))
    • 2. Event System(本地事件与分布式事件分发)
    • 3. IoC(自动匹配功能,实例数量限制功能)
    • 4. Sql Dispatcher System(基于Sql server的读写分离系统)
    • 5. Session System(分布式Session系统)
    • 6. 分布式Command Bus(MSMQ实现,解决4M限制,支持Session的读取)
    • 7. 规则引擎
     
    分类: A2D Framework
  • 相关阅读:
    sublime 2/3 for mac link to command
    语言设计中的鸭子类型风格
    Android布局分析工具HierarchyView的使用方法
    自定义的圆形ProgressBar
    自动移动的ImageView
    Shape 各种属性详解
    用GridLayout实现计算器的布局
    Toast的用法(可以设置显示时间,自定义布局的,线程中的Toast)
    Shape画圆形控件
    用ImageSwitcher实现显示图片(更改图片时有动画效果)
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/3308009.html
Copyright © 2020-2023  润新知