<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>冒号空间 &#187; 规则引擎</title>
	<atom:link href="http://blog.zhenghui.org/tag/rule-engine/feed/" rel="self" type="application/rss+xml" />
	<link>http://blog.zhenghui.org</link>
	<description>自然、人类、机器</description>
	<lastBuildDate>Fri, 30 Dec 2011 03:14:59 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3</generator>
		<item>
		<title>冒号课堂§4.4：情景范式</title>
		<link>http://blog.zhenghui.org/2009/09/19/colon-class-4_4/</link>
		<comments>http://blog.zhenghui.org/2009/09/19/colon-class-4_4/#comments</comments>
		<pubDate>Sat, 19 Sep 2009 04:21:30 +0000</pubDate>
		<dc:creator>hui</dc:creator>
				<category><![CDATA[冒号课堂]]></category>
		<category><![CDATA[情景编程]]></category>
		<category><![CDATA[编程范式]]></category>
		<category><![CDATA[规则引擎]]></category>
		<category><![CDATA[闭包]]></category>

		<guid isPermaLink="false">http://blog.zhenghui.org/?p=432</guid>
		<description><![CDATA[<b>情景范式</b>——餐馆里的编程范式（<em>编程范式在餐馆中的应用</em>）<br/> • 厨师只需提供一种服务：把纸上菜变成盘中菜，至于蒸、煮、炒、炖等具体做法纯属实现细节<br/> • 可以这么理解（闭包）：所谓包，指函数与其周围的环境变量捆绑打包；所谓闭，指这些变量是封闭的，只能为该函数所专用<br/> • 合理地使用闭包能使代码更加简洁清晰，散发出函数式特有的优雅气质<br/> • 换盘子有两种方式：一种是服务员主动换，一种是客人要求换。前者是轮询，后者是通知<br/> • 如果把待加工的菜看作数据，技法看作算法，将数据与算法分离，以算法为中心，那是什么范式？ [...]]]></description>
			<content:encoded><![CDATA[<h1 style="text-align: center"><span style="font-family: 宋体">冒号课堂</span></h1>
<strong><span style="font-size: 13pt; font-family: 宋体">第四课 重温范式(4)</span></strong>

<!-- below comes from generated html -->
<head><link rel="stylesheet" href="http://blog.zhenghui.org/css/colonclass.css" type="text/css"></head>

<div lang="zh-CN" class="article" title="情景范式"><div class="titlepage"><div><div><h1 class="title"><a name="id639173"></a>4.4 情景范式——餐馆里的编程范式</h1></div><div><div class="author"><h3 class="author">郑晖</h3></div></div><div><div class="abstract" title="摘要"><p class="title"><b>摘要</b></p><p>编程范式在餐馆中的应用</p></div></div></div><hr /></div><div class="toc"><p><b>目录</b></p><dl><dt><span class="section"><a href="#preview">！预览</a></span></dt><dt><span class="section"><a href="#question">？提问</a></span></dt><dt><span class="section"><a href="#explaination">：讲解</a></span></dt><dt><span class="section"><a href="#note">，插语</a></span></dt><dt><span class="section"><a href="#summary">。总结</a></span></dt><dt><span class="section"><a href="#reference">“”参考</a></span></dt></dl></div><div class="epigraph"><div class="literallayout"><p>理论是认生的孩童，多陪他玩玩，自会活泼起来</p></div><div class="attribution"><span>—<span class="attribution">题记</span></span></div></div><div class="section" title="！预览"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="preview"></a>！预览</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    厨师只需提供一种服务：把纸上菜变成盘中菜，至于蒸、煮、炒、炖等具体做法纯属实现细节
                </p></li><li class="listitem"><p>
                    可以这么理解（闭包）：所谓包，指函数与其周围的环境变量捆绑打包；所谓闭，指这些变量是封闭的，只能为该函数所专用
                </p></li><li class="listitem"><p>
                    合理地使用闭包能使代码更加简洁清晰，散发出函数式特有的优雅气质
                </p></li><li class="listitem"><p>
                    换盘子有两种方式：一种是服务员主动换，一种是客人要求换。前者是轮询，后者是通知
                </p></li><li class="listitem"><p>
                    如果把待加工的菜看作数据，技法看作算法，将数据与算法分离，以算法为中心，那是什么范式？
                </p></li></ul></div></div><div class="section" title="？提问"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="question"></a>？提问</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>什么是闭包？为什么被称为闭包？它有什么作用？</p></li><li class="listitem"><p>规则引擎有何用处？</p></li><li class="listitem"><p>能否设想一个生活中的场景，把介绍的九种编程范式都用上？</p></li></ul></div></div><div class="section" title="：讲解"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="explaination"></a>：讲解</h2></div></div></div><p>
            叹号摘下眼镜，揉了揉眼：“范式再好，多了也难免有些审美疲劳。” 
        </p><p>
            逗号也搓着太阳穴：“这段时间脑子被灌得沉甸甸的。”
        </p><p>
            “彼此彼此！你们的脑袋老闹涝灾，我的喉咙老闹旱灾。”冒号说着，拿起矿泉水瓶一饮而尽。
        </p><p>
            大伙听着怪别扭的，这不是拐着弯说我们脑子进水了吗？
        </p><p>
            冒号清了清嗓子：“为尊重民意，也为避免消化不良，大家先轻松一下。下面我们来个<span class="strong"><strong>情景编程</strong></span>。”
        </p><p>
            “情景编程？没听说过，只听说过情景英语。”问号感到挺新鲜。
        </p><p>
            “都是学语言嘛，有何两样？”冒号轻描淡写，“让我们试着用生活中的实例将一些编程范式串联起来。前面提到，OOP可以看作管理一个服务型公司，现在以餐馆为例，你们每人设计一类对象及其提供的服务。”
        </p><p>
            问号来了兴致：“我先来吧。构造一个前台接待员，负责迎客、引座、送客。”
        </p><p>
            句号很是不满：“还真不客气，上来就把最漂亮的对象抢走了。”
        </p><p>
            台下一阵笑声。
        </p><p>
            “我来构建最常见的服务员。”逗号一捋袖子，一副准备开干的样子，“负责斟茶、写菜、上菜、换盘。”
        </p><p>
            “嗯，很熟练。”冒号一本正经。
        </p><p>
            句号实在得很：“我设计收银员，专管收帐、出具发票。”
        </p><p>
            引号颇为自豪：“我造一个技术含量最高的大厨，专门负责烹调。”
        </p><p>
            逗号不服：“你倒简单，那么高的技术含量，敢情炒肉和炖肉一个做法啊？”
        </p><p>
            引号自觉理亏：“那就负责蒸、煮、炒、炖吧。”
        </p><p>
            冒号为其辩护：“引号同学并没有错，可惜没能坚持。厨师只需提供一种服务：把纸上菜变成盘中菜，至于蒸、煮、炒、炖等具体做法纯属实现细节。”
        </p><p>
            叹号有点委屈：“唉，看来我只好做技术含量最低的厨工了，负责食品预加工、洗碗、打扫清洁。”
        </p><p>
            冒号将大家设计的类翻译成Java代码——
        </p><div class="informalexample"><pre class="programlisting">
// 前台接待员
Class Receptionist
{
    public void receive(Customer customer)  {…} // 迎客
    public void usher(Customer customer)    {…} // 引座
    public void send(Customer customer)	    {…} // 送客
}

// 服务员
Class Waiter
{
    public void pourTea(Customer customer)             {…} // 斟茶
    public List&lt;Order&gt; write(Customer customer)        {…} // 写菜
    public void serve(Customer customer, Course course){…} // 上菜
    public void exchangePlate(Customer customer)       {…} // 换盘
}

// 收银员
Class Cashier
{
    public void charge(Customer customer)	{…} // 收帐
    public void issueInvoice(Customer customer) {…} // 出具发票
}

// 厨师
Class Cook
{
    public Course cook(Order order)		{…} // 烹调
}

// 厨工
Class KitchenHand
{
    public void prepareFood()			{…} // 准备食品
    public void washDishes()			{…} // 洗碗
    public void clean()				{…} // 打扫清洁
}</pre></div><p>
            “你们造人，我来造物。”冒号构造了一个餐馆的类——
        </p><div class="informalexample"><pre class="programlisting">
// 餐馆
Class Restaurant
{
    // 每当有顾客来访，返回该顾客
    private Customer accept() {…}
 
    // 为指定顾客提供所有的餐馆服务
    private void serve(Customer customer) {…}

    // 餐馆服务
    public void service()
    {
        while (true) // 无限循环，假设餐馆7×24小时营业
        {
            final Customer customer;
            if ((customer = accept() ) != null) // 某顾客来访
            {
                serve(customer);  // 为该顾客提供服务
            }
        }
    }
}</pre></div><p>
            冒号解说道：“这里accept类似Socket的accept，属于堵塞呼叫，意味着此方法将堵塞进程直至收到新数据。为简单计，把一行顾客当作一个Customer。大家对此段代码有何看法？”
        </p><p>
            “没什么，很简单啊。”逗号说完补充一句，“关键是serve方法的实现。”
        </p><p>
            “这里我们明显用到了两个范式，<span class="emphasis"><em>对象式</em></span>和<span class="emphasis"><em>过程式</em></span>。”冒号提示道。
        </p><p>
            引号会意：“应该还需要并发式。serve如果与service在同一线程中运行，那么餐馆只有等服务完一个Customer后才能服务后面的，这显然是荒唐的。”
        </p><p>
            “对极了！”冒号将“serve(customer);”改写为——
        </p><div class="informalexample"><pre class="programlisting">
// serve(customer);  // 错误地使用单线程！
new Thread           // 构造一个线程
    (new Runnable()
    {
        public void run(){ Restaurant.this.serve(customer); }
    }).start();         // 启动该线程 </pre></div><p>
            冒号道：“这回serve在新线程中运行，不会耽误Restaurant服务下一位Customer了。”
        </p><p>
            问号眼尖：“我注意到声明customer时前面加上了关键字final，有必要吗？”
        </p><p>
            “如果不用线程，是不必要的。”冒号回应道，“我们在建造线程时用到了实现Runnable接口的<span class="term">匿名类</span>（anonymous class），它是涉及到<span class="emphasis"><em>局部变量</em></span>customer的<span class="term">内部类</span>（inner class），Java语法要求该局部变量必须是final类型。值得一提的是，这里不仅用到了<span class="emphasis"><em>并发式</em></span>，而且与<span class="emphasis"><em>函数式</em></span>也密切相关。”
        </p><p>
            “函数式？”逗号奇道。
        </p><p>
            “不错。”冒号坚定地点着头，“我们不是提过函数式中的函数是头等公民吗？也就是说，函数与其他基本数据类型一样，可以作为传递参数、返回值或与变量名绑定。<span class="term">闭包</span>（closure）便是这样一种函数，并且还能保留当初创建时周围的环境变量。以上匿名类本质上是函数serve的包装，经实例化后作为参数传入Thread的构造函数，并且记住了外部类的局部变量customer——这也是为什么它必须是final以保证不被重新赋值的原因。应该说这是一种OO化的闭包形式，预计在Java 7中它的用法会更简洁，这也意味着Java代码中将飘进更多的函数式风味。”
        </p><p>
            引号喃喃道：“以前只听说过数学里有个闭包的概念。”
        </p><p>
            冒号略加指点：“可以这么理解：所谓<span class="emphasis"><em>包</em></span>，指函数与其周围的环境变量捆绑打包；所谓<span class="emphasis"><em>闭</em></span>，指这些变量是封闭的，只能为该函数所专用。如果你真懂数学，就会发现它们本质上是相通的。”
        </p><p>
            叹号隐隐约约地觉得：“把函数与变量捆绑起来，怎么听起来像是OOP的做法啊？”
        </p><p>
            “嗯，的确相似。”冒号微颔，“不妨认为闭包就是封装了环境变量的<span class="emphasis"><em>隐形对象</em></span>的方法——通常是匿名方法。我们用一段JavaScript代码来加深印象——”
        </p><div class="informalexample"><pre class="programlisting">
/* 返回函数f的近似导函数 */
function derivative(f) 
{  // dx最好作为参数传入，放在此处主要是为了说明闭包的用法
    var dx = 0.00001;  // dx越小，近似度越高
    return function(x) { return (f(x + dx) - f(x)) / dx; };
} 

/* 返回一个数的平方数 */
function square(x) { return x * x; }

/* 返回一个数的双倍数  */
function double(x) { return 2 * x; }

/* 对任何一个不大的数值变量x（比如小于100），下列函数的返回值应该非常接近于零 */
function testSquareDerivative(x) { return derivative(square) (x) - double(x); } </pre></div><p>
            叹号感到有点头痛：“怎么跑出了微积分？大学学的那点高数早就还给老师了。”
        </p><p>
            冒号笑着安慰他：“还给老师没关系，我再借给你一点：平方函数的导数是双倍函数。因此，函数derivative(square)应该很接近函数double的作用效果。作为检验，testSquareDerivative能将任何一个不大的数映射到近似于零的数<a class="link" href="#note1"><sup>[1]</sup></a>。”
        </p><p>
            引号这下彻底明白了：“在求导函数derivative中，传入的参数f和返回值都是函数，这是函数作为头等公民的特征。其中返回的匿名函数就是闭包，它附着了两个环境变量：外层函数的传入参数f和局部变量dx。”
        </p><p>
            “完全正确！”冒号作出积极的肯定，“如果不是闭包，这两个环境变量在derivative返回后就会失去效用。由此可见，合理地使用闭包能使代码更加简洁清晰，散发出函数式特有的优雅气质。”
        </p><p>
            句号有些按捺不住编程的冲动，自告奋勇：“我来具体实现餐馆的serve方法吧。”
        </p><p>
            得到冒号的默许，句号在黑板上写下——
        </p><div class="informalexample"><pre class="programlisting">
private void serve(Customer customer)
{
    // 找一个空闲的接待员
    Receptionist receptionist = findReceptionist();
    receptionist.receive(customer);
    receptionist.usher(customer);
    // 找一个空闲的服务员
    Waiter waiter = findWaiter();
    waiter.pourTea(customer);
    List&lt;Order&gt; orders = waiter.write(customer);
    // 将菜单交给一位厨师
    Cook cook = waiter.pass(orders);
    for (Order order : orders) // 厨师照单做菜
    {
        Course course = cook.cook(order);
        // 找一个空闲的服务员
        waiter = findWaiter();
        // 服务员上菜
        waiter.serve(customer, course); 
        // 顾客开始享用
        customer.eat(course); 
    }

    // 顾客用餐完毕。。。
    // 找一个空闲的收银员
    Cashier cashier = findCashier();
    cashier.charge(customer);
    cashier.issueInvoice(customer);
    // 找一个空闲的接待员
    receptionist = findReceptionist();
    receptionist.send(customer);
} </pre></div><p>
            句号写毕又复查一遍，拍拍手上的粉笔灰，心满意足地走下台来。
        </p><p>
            叹号提意见：“我的厨工没派上用场，应该在厨师烹调前调用KitchenHand的prepareFood方法。”
        </p><p>
            问号挑出另外的毛病：“在for循环中，厨师、服务员和顾客的行为应该在不同的线程中，厨师不可能等服务员上完一道菜或顾客吃完一道菜后才做下一道。”
        </p><p>
            “可能更复杂呢！”逗号也来凑热闹，“一位顾客点的几样菜可能分别由几位厨师同时做，每位厨师都在不同的线程中工作。”
        </p><p>
            引号更严谨：“还应有一个后台线程，让服务员（Waiter）随时换盘（exchangePlate），让厨工（KitchenHand）随时洗盘（washDishes）和清洁（clean），这样所有服务人员提供的服务都用上了。”
        </p><p>
            句号倒抽凉气：“估不到漏洞这么多，并发式真是无处不在啊。”
        </p><p>
            冒号继续点拨：“换盘子有两种方式：一种是服务员主动换，一种是客人要求换。前者是轮询，后者是通知。”
        </p><p>
            “哦，<span class="emphasis"><em>事件驱动式</em></span>！”句号迅即反应过来，“客人是事件源，服务员是事件处理器，客人不定期地招手呼唤是在发表事件以通知服务员。客人与服务员是多对多的松耦合关系。”
        </p><p>
            冒号点点头，又指着引号：“刚才有人不满你的大厨职责过于简单，现在你来实现一下，也好显显技术含量。”
        </p><p>
            引号在台上摸了半天头，编出一段代码——
        </p><div class="informalexample"><pre class="programlisting">
Class Cook
{
    public Course cook(Order order) 
    {
        // 根据菜单查食谱
        Recipe recipe = lookupRecipe(order);
        // 找到食谱的烹调步骤
        List&lt;Instruction&gt; instructions = recipe.getInstructions();
        for (Instruction instruction : instructions)
        {
            follow(instruction); // 按食谱的指令操作
        }
    }
} </pre></div><p>
            “堂堂大厨原来是靠查食谱做菜的。”逗号揶揄道。
        </p><p>
            引号为难地说：“这不是在编程嘛，好端端的人脑，不得不去模拟电脑，完全搞倒了。”
        </p><p>
            “要设计会烹调的机器人，兴许还真得这样呢。”冒号笑道，“不过由于各种菜式组合繁多，如果每种菜都配菜谱未免太庞杂，如何精简呢？”
        </p><p>
            句号建议：“菜式成千上万，烹调技法相对少许多，不妨以技法为主线。”
        </p><p>
            “好主意！”冒号挑起大拇指，“如果把待加工的菜看作数据，技法看作算法，将数据与算法分离，以算法为中心，那是什么范式？”
        </p><p>
            “<span class="emphasis"><em>泛型式</em></span>！”大家异口同声。
        </p><p>
            “至此我们已涉及了过程式、对象式、并发式、函数式、事件驱动式和泛型式。”引号扳着手指算着，“还差逻辑式、元编程和切面式了。”
        </p><p>
            冒号把目光转向逗号：“写菜单并不容易，如果客人不直接点菜，你的服务员如何向他推荐？”
        </p><p>
            逗号答：“最简单的方法是报菜名，并一一询问客人。”
        </p><p>
            冒号皱眉：“这样你是简单了：一个迭代就完事，可客人也该发火了。”
        </p><p>
            逗号赶紧修正：“先询问客人的口味、忌讳等等，再向他建议一些菜式。”
        </p><p>
            “这还差不多。”冒号眉头舒展开来，“考虑到客人的口味、忌讳等各有不同，餐馆的菜单也随时可能变化，如果把这些都硬编码（hardcode），再加上层层叠叠的if-else语句，代码将成为懒婆娘的裹脚——又臭又长又难维护。”
        </p><p>
            引号提议：“可以把这些信息预先存入数据库，届时用SQL查询。”
        </p><p>
            “想法很好，只是有一点难度。”冒号提醒道， “这些信息并非简单的对应关系，包含一些逻辑推理，甚至需要一些模糊判断。”
        </p><p>
            句号一拍大腿：“前面不是提到领域特定语言DSL吗？将所有规则用自定义的DSL编写，再利用<span class="emphasis"><em>元编程</em></span>转换成C、Java之类的通用语言，不是很好吗？”
        </p><p>
            “棒极了！”冒号不吝赞词，“不过还有一种思路。我们可以搜集餐馆的菜式、顾客口味、忌讳以及各种菜与口味、忌讳之间的关系等等一系列事实和规则，用<span class="term">规则语言</span>（Rule Language）来描述，通过<span class="term">规则引擎</span>（Rule Engine）来导出符合顾客需求的菜肴。这种方式将业务规则与应用程序分离、将知识表示与逻辑实现分离，是SoC原理的一种应用，同时也是一种<span class="emphasis"><em>逻辑式</em></span>编程。”
        </p><p>
            问号关心地问：“这些规则引擎与Java程序兼容吗？”
        </p><p>
            冒号回答：“不少规则引擎用Java实现或专为Java平台设计，如Jess、Drools、JLisa、JRules等，Sun还发布了javax.rules API（JSR 94）以统一对各类引擎的访问接口。另外在.NET平台上也有业务规则引擎，Microsoft Business Rule Engine（MS BRE）和Windows Workflow Foundation （WF）中的WF Rules均提供了业务规则引擎。”
        </p><p>
            引号颇感意外：“既然是逻辑式编程，为什么不采用代表语言Prolog呢？”
        </p><p>
            冒号准备了一大段理由等着他：“刚才提到的规则引擎多是基于Rete算法<a class="link" href="#note2"><sup>[2]</sup></a>的，主要采用<span class="emphasis"><em>数据驱动</em></span>（data-driven）的<span class="term">正向推理</span>（forward chaining）法，而Prolog引擎采用<span class="emphasis"><em>目标驱动</em></span>（goal-driven）的<span class="term">逆向推理</span>（backward chaining）法。正向推理<span class="emphasis"><em>自底向上</em></span>，利用推理规则从已有的事实数据推出更多的数据，直到达成目标；逆向推理正相反，<span class="emphasis"><em>自顶向下</em></span>，从目标出发寻找满足结论的事实<a class="link" href="#note3"><sup>[3]</sup></a>。相比而言，正向推理适合针对不同输入作出不同反应，而逆向推理适合回答查询。现在是服务员根据客人的喜好提建议，当然用正向推理更合适。再说这类引擎与Java的集成更加方便，因此我们没有选择Prolog。”
        </p><p>
            讲到此处，每个人都意识到，只剩下最后一个范式了。
        </p><p>
            冒号提出一个新问题：“假如餐馆经理接到顾客投诉，反映服务人员态度不好，卫生状况也不理想，应该怎么办？”
        </p><p>
            问号抢先说：“首先我的接待员在迎客（receive）时要笑容可掬地对顾客说：‘欢迎光临！’，在送客（send）时要对顾客鞠躬：‘请慢走，欢迎下次再来’”
        </p><p>
            逗号接着说：“我的服务员在上完菜后应对客人说：‘请慢用’，句号的收银员也应加些礼貌用语，让人家高高兴兴地掏钱。”
        </p><p>
            句号补充道：“服务员在上菜（serve）前、厨师在烹饪（cook）前应洗手，厨工在洗碗（washDishes）后应对餐具消毒。”
        </p><p>
            冒号紧接着问：“如果餐馆对礼貌规范或卫生标准做修改，必然要牵扯不同类中的不同的方法，维护起来很不方便，怎样才能有效地解决这个问题呢？”
        </p><p>
            答案已经昭然若揭了。
        </p><p>
            冒号干脆自问自答：“不错，正是用<span class="emphasis"><em>切面式</em></span>编程。只要创立两个Aspect：Etiquette和Sanitation，分别负责礼貌规范和卫生标准方面的事务。一旦某一方面的要求发生变化，比如餐馆来了外宾，或者碰上非典或禽流感，只需在相应的Aspect模块中作调整：将礼貌用语换成英语或者提高卫生标准等等。如果采用runtime AOP，甚至还可在<span class="emphasis"><em>运行期</em></span>选择激活或禁用这些Aspect。”
        </p><p>
            下面开始有些骚动，大伙早已脑中满满而腹中空空，有点头重脚轻了。
        </p><p>
            冒号见状，遂发出激动人心的号召：“今天的课到此结束，让我们从虚拟的餐馆中走出，到真实的餐馆中去吧！”
        </p><p>
            众人齐声欢呼。
        </p></div><div class="section" title="，插语"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="note"></a>，插语</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p><a name="note1"></a>
                    若输入数过大，则需要设定更小的dx。此外，还可能产生计算溢出。
                </p></li><li class="listitem"><p><a name="note2"></a>
                    Rete算法是一种高效的模式匹配算法，用于实现规则生成系统（production rule system）。文中提到的规则引擎除WF Rules外都是基于该算法的。
                </p></li><li class="listitem"><p><a name="note3"></a>
                    用形式逻辑的语言来说，正向推理顺着从前件（即if语句）到后件（即then语句）的方向，逆向推理顺着从后件到前件的方向。
                </p></li></ol></div></div><div class="section" title="。总结"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="summary"></a>。总结</h2></div></div></div><div class="itemizedlist"><ul class="itemizedlist" type="disc"><li class="listitem"><p>
                    闭包是一种能保留当初创建时的环境变量的函数。它通常以匿名的方式存在，多用于函数式编程中，能使代码更加简洁清晰。Java中的匿名类可以看作OO化的闭包形式。
                </p></li><li class="listitem"><p>
                    Java平台上的Jess、Drools、JLisa、JRules和.NET平台上的MS BRE、WF Rules都是规则引擎，主要基于正向推理。它们提供了逻辑式编程环境，能有效地将业务规则从应用程序中分离出来，提高了软件的灵活性和可维护性。
                </p></li><li class="listitem"><p>
                    每种编程范式都能在生活中找到它的应用，它们本来就是人类思维方式的投影。
                </p></li></ul></div></div><div class="section" title="“”参考"><div class="titlepage"><div><div><h2 class="title" style="clear: both"><a name="reference"></a>“”参考</h2></div></div></div><div class="orderedlist"><ol class="orderedlist" type="1"><li class="listitem"><p>
                    Wikipedia．Closure (computer science)．<a class="link" href="http://en.wikipedia.org/wiki/Closure_(computer_science)" target="_top">http://en.wikipedia.org/wiki/Closure_(computer_science)</a>
                </p></li><li class="listitem"><p>
                    Ernest Friedman-Hill．Jess 7.1p2 manual．<a class="link" href="http://www.jessrules.com/jess/docs/Jess71p2.pdf" target="_top">http://www.jessrules.com/jess/docs/Jess71p2.pdf</a>
                </p></li><li class="listitem"><p>
                    Mark Proctor等．Drools Documentation．<a class="link" href="http://downloads.jboss.com/drools/docs/4.0.7.19894.GA/html_single/index.html" target="_top">http://downloads.jboss.com/drools/docs/4.0.7.19894.GA/html_single/index.html</a>
                </p></li></ol></div></div></div>

<!-- below is edited manually -->
<strong><span style="font-family: 宋体">课后思考</span></strong>
<ul style="margin-top: 0cm; list-style-type: none">
    <li>
        04-01 通过本课的介绍，你对函数范式与逻辑范式是否有了进一步的认识？它们的思想能否应用在你所熟悉的过程式或对象式语言当中？
    </li>
    <li>
        04-02 同样一个问题用不同的语言来编程，代码可能会有极大的差异。你认为这种差异的主要根源是语言还是范式？
    </li>
    <li>
        04-03 认真研究本课中的编程范式汇总表，并补充新的内容，如各范式的关键词、理论基础、最佳实践、注意事项等等。
    </li>
    <li>
        04-04 掌握编程范式对语言学习和编程设计有何实际意义？
    </li>
</ul><p><a class="a2a_dd a2a_target addtoany_share_save" href="http://www.addtoany.com/share_save#url=http%3A%2F%2Fblog.zhenghui.org%2F2009%2F09%2F19%2Fcolon-class-4_4%2F&amp;title=%E5%86%92%E5%8F%B7%E8%AF%BE%E5%A0%82%C2%A74.4%EF%BC%9A%E6%83%85%E6%99%AF%E8%8C%83%E5%BC%8F" id="wpa2a_2">分享/保存</a></p><h3  class="related_post_title">相关文章</h3><ul class="related_post"><li>2009年09月21日 -- <a href="http://blog.zhenghui.org/2009/09/21/colon-class-5_1/" title="冒号课堂§5.1：教学计划">冒号课堂§5.1：教学计划</a> (1)</li><li>2009年09月17日 -- <a href="http://blog.zhenghui.org/2009/09/17/colon-class-4_3/" title="冒号课堂§4.3：汇总范式">冒号课堂§4.3：汇总范式</a> (5)</li><li>2009年09月15日 -- <a href="http://blog.zhenghui.org/2009/09/15/colon-class-4_2/" title="冒号课堂§4.2：逻辑范式">冒号课堂§4.2：逻辑范式</a> (0)</li><li>2009年09月13日 -- <a href="http://blog.zhenghui.org/2009/09/13/colon-class-4_1/" title="冒号课堂§4.1：函数范式">冒号课堂§4.1：函数范式</a> (0)</li><li>2009年09月11日 -- <a href="http://blog.zhenghui.org/2009/09/11/colon-class-3_4/" title="冒号课堂§3.4：事件驱动">冒号课堂§3.4：事件驱动</a> (2)</li><li>2009年09月10日 -- <a href="http://blog.zhenghui.org/2009/09/10/colon-class-3_3/" title="冒号课堂§3.3：切面范式">冒号课堂§3.3：切面范式</a> (4)</li><li>2009年09月9日 -- <a href="http://blog.zhenghui.org/2009/09/09/colon-class-3_2/" title="冒号课堂§3.2：超级范式">冒号课堂§3.2：超级范式</a> (2)</li><li>2009年09月8日 -- <a href="http://blog.zhenghui.org/2009/09/08/colon-class-3_1/" title="冒号课堂§3.1：泛型范式">冒号课堂§3.1：泛型范式</a> (5)</li><li>2009年09月7日 -- <a href="http://blog.zhenghui.org/2009/09/07/colon-class-2_4/" title="冒号课堂§2.4：并发范式">冒号课堂§2.4：并发范式</a> (2)</li><li>2009年09月6日 -- <a href="http://blog.zhenghui.org/2009/09/06/colon-class-2_3/" title="冒号课堂§2.3：对象范式">冒号课堂§2.3：对象范式</a> (3)</li></ul>]]></content:encoded>
			<wfw:commentRss>http://blog.zhenghui.org/2009/09/19/colon-class-4_4/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

