冒號(hào)課堂§4.4:情景范式

           

          冒號(hào)課堂

          第四課 重溫范式(4)


          4.4
          情景范式——餐館里的編程范式

          理論是認(rèn)生的孩童,多陪他玩玩,自會(huì)活潑起來(lái)                             ——題記

           

          關(guān)鍵詞:      編程范式,情景編程

          摘要:   編程范式在餐館中的應(yīng)用

           

            提問(wèn)

           

          l        什么是閉包?為什么被稱為閉包?它有什么作用?

          l        規(guī)則引擎有何用處?

          l        能否設(shè)想一個(gè)生活中的場(chǎng)景,把介紹的九種編程范式都用上?

             
          講解


          嘆號(hào)摘下眼鏡,揉了揉眼:“范式再好,多了也難免有些審美疲勞。”

          逗號(hào)也搓著太陽(yáng)穴:“這段時(shí)間腦子被灌得沉甸甸的。”

          “彼此彼此!你們的腦袋老鬧澇災(zāi),我的喉嚨老鬧旱災(zāi)。”冒號(hào)說(shuō)著,拿起礦泉水瓶一飲而盡。

          大伙聽(tīng)著怪別扭的,這不是拐著彎說(shuō)我們腦子進(jìn)水了嗎?

          冒號(hào)清了清嗓子:“為尊重民意,也為避免消化不良,大家先輕松一下。下面我們來(lái)個(gè)情景編程。”

          “情景編程?沒(méi)聽(tīng)說(shuō)過(guò),只聽(tīng)說(shuō)過(guò)情景英語(yǔ)。”問(wèn)號(hào)感到挺新鮮。

          “都是學(xué)語(yǔ)言嘛,有何兩樣?”冒號(hào)輕描淡寫(xiě),“讓我們?cè)囍蒙钪械膶?shí)例將一些編程范式串聯(lián)起來(lái)。前面提到,OOP可以看作管理一個(gè)服務(wù)型公司,現(xiàn)在以餐館為例,你們每人設(shè)計(jì)一類(lèi)對(duì)象及其提供的服務(wù)。”

          問(wèn)號(hào)來(lái)了興致:“我先來(lái)吧。構(gòu)造一個(gè)前臺(tái)接待員,負(fù)責(zé)迎客、引座、送客。”

          句號(hào)很是不滿:“還真不客氣,上來(lái)就把最漂亮的對(duì)象搶走了。”

          臺(tái)下一陣笑聲。

          “我來(lái)構(gòu)建最常見(jiàn)的服務(wù)員。”逗號(hào)一捋袖子,一副準(zhǔn)備開(kāi)干的樣子,“負(fù)責(zé)斟茶、寫(xiě)菜、上菜、換盤(pán)。”

          “嗯,很熟練。”冒號(hào)一本正經(jīng)。

          句號(hào)實(shí)在得很:“我設(shè)計(jì)收銀員,專管收帳、出具發(fā)票。”

          引號(hào)頗為自豪:“我造一個(gè)技術(shù)含量最高的大廚,專門(mén)負(fù)責(zé)烹調(diào)。”

          逗號(hào)不服:“你倒簡(jiǎn)單,那么高的技術(shù)含量,敢情炒肉和燉肉一個(gè)做法啊?”

          引號(hào)自覺(jué)理虧:“那就負(fù)責(zé)蒸、煮、炒、燉吧。”

          冒號(hào)為其辯護(hù):“引號(hào)同學(xué)并沒(méi)有錯(cuò),可惜沒(méi)能堅(jiān)持。廚師只需提供一種服務(wù):把紙上菜變成盤(pán)中菜,至于蒸、煮、炒、燉等具體做法純屬實(shí)現(xiàn)細(xì)節(jié)。”

          嘆號(hào)有點(diǎn)委屈:“唉,看來(lái)我只好做技術(shù)含量最低的廚工了,負(fù)責(zé)食品預(yù)加工、洗碗、打掃清潔。”

          冒號(hào)將大家設(shè)計(jì)的類(lèi)翻譯成Java代碼——

          // 前臺(tái)接待員

          Class Receptionist

          {

          public void receive(Customer customer)        {…} // 迎客

          public void usher(Customer customer) {…} // 引座

          public void send(Customer customer)   {…} // 送客

          }

          // 服務(wù)員

          Class Waiter

          {

          public void pourTea(Customer customer)       {…} // 斟茶

          public List<Order> write(Customer customer){…} // 寫(xiě)菜

          public void serve(Customer customer, Course course){…} // 上菜

          public void exchangePlate(Customer customer) {…} // 換盤(pán)

          }

          // 收銀員

          Class Cashier

          {

          public void charge(Customer customer)       {…} // 收帳

          public void issueInvoice(Customer customer){…} // 出具發(fā)票

          }

          // 廚師

          Class Cook

          {

          public Course cook(Order order)           {…} // 烹調(diào)

          }

          // 廚工

          Class KitchenHand

          {

          public void prepareFood()                {…} // 準(zhǔn)備食品

          public void washDishes()                {…} // 洗碗

          public void clean()                            {…} // 打掃清潔

          }

          “你們?cè)烊耍襾?lái)造物。”冒號(hào)構(gòu)造了一個(gè)餐館的類(lèi)——

          // 餐館

          Class Restaurant

          {

          // 每當(dāng)有顧客來(lái)訪,返回該顧客

          private Customer accept() {…}

           

          // 為指定顧客提供所有的餐館服務(wù)

          private void serve(Customer customer) {…}

          // 餐館服務(wù)

          public void service()

          {

                 while (true) // 無(wú)限循環(huán),假設(shè)餐館7×24小時(shí)營(yíng)業(yè)

                 {

                         final Customer customer;

                         if ((customer = accept() ) != null) // 某顧客來(lái)訪

                         {

                                serve(customer); // 為該顧客提供服務(wù)

          }

          }

          }

          }

          冒號(hào)解說(shuō)道:“這里accept類(lèi)似Socketaccept,屬于堵塞呼叫,意味著此方法將堵塞進(jìn)程直至收到新數(shù)據(jù)。為簡(jiǎn)單計(jì),把一行顧客當(dāng)作一個(gè)Customer。大家對(duì)此段代碼有何看法?”

          “沒(méi)什么,很簡(jiǎn)單啊。”逗號(hào)說(shuō)完補(bǔ)充一句,“關(guān)鍵是serve方法的實(shí)現(xiàn)。”

          “這里我們明顯用到了兩個(gè)范式,對(duì)象式過(guò)程式。”冒號(hào)提示道。

          引號(hào)會(huì)意:“應(yīng)該還需要并發(fā)式。serve如果與service在同一線程中運(yùn)行,那么餐館只有等服務(wù)完一個(gè)Customer后才能服務(wù)后面的,這顯然是荒唐的。”

          “對(duì)極了!”冒號(hào)將“serve(customer);”改寫(xiě)為——

          // serve(customer);  // 錯(cuò)誤地使用單線程!

          new Thread              // 構(gòu)造一個(gè)線程

          (new Runnable()

          {

                  public void run(){ Restaurant.this.serve(customer); }

          }).start();         // 啟動(dòng)該線程

          冒號(hào)道:“這回serve在新線程中運(yùn)行,不會(huì)耽誤Restaurant服務(wù)下一位Customer了。”

          問(wèn)號(hào)眼尖:“我注意到聲明customer時(shí)前面加上了關(guān)鍵字final,有必要嗎?”

          “如果不用線程,是不必要的。”冒號(hào)回應(yīng)道,“我們?cè)诮ㄔ炀€程時(shí)用到了實(shí)現(xiàn)Runnable接口的匿名類(lèi)anonymous class),它是涉及到局部變量customer內(nèi)部類(lèi)inner class),Java語(yǔ)法要求該局部變量必須是final類(lèi)型。值得一提的是,這里不僅用到了并發(fā)式,而且與函數(shù)式也密切相關(guān)。”

          “函數(shù)式?”逗號(hào)奇道。

          “不錯(cuò)。”冒號(hào)堅(jiān)定地點(diǎn)著頭,“我們不是提過(guò)函數(shù)式中的函數(shù)是頭等公民嗎?也就是說(shuō),函數(shù)與其他基本數(shù)據(jù)類(lèi)型一樣,可以作為傳遞參數(shù)、返回值或與變量名綁定。閉包closure)便是這樣一種函數(shù),并且還能保留當(dāng)初創(chuàng)建時(shí)周?chē)沫h(huán)境變量。以上匿名類(lèi)本質(zhì)上是函數(shù)serve的包裝,經(jīng)實(shí)例化后作為參數(shù)傳入Thread的構(gòu)造函數(shù),并且記住了外部類(lèi)的局部變量customer——這也是為什么它必須是final以保證不被重新賦值的原因。應(yīng)該說(shuō)這是一種OO化的閉包形式,預(yù)計(jì)在Java 7中它的用法會(huì)更簡(jiǎn)潔,這也意味著Java代碼中將飄進(jìn)更多的函數(shù)式風(fēng)味。”

          引號(hào)喃喃道:“以前只聽(tīng)說(shuō)過(guò)數(shù)學(xué)里有個(gè)閉包的概念。”

          冒號(hào)略加指點(diǎn):“可以這么理解:所謂,指函數(shù)與其周?chē)沫h(huán)境變量捆綁打包;所謂,指這些變量是封閉的,只能為該函數(shù)所專用。如果你真懂?dāng)?shù)學(xué),就會(huì)發(fā)現(xiàn)它們本質(zhì)上是相通的。”

          嘆號(hào)隱隱約約地覺(jué)得:“把函數(shù)與變量捆綁起來(lái),怎么聽(tīng)起來(lái)像是OOP啊?”

          “嗯,的確相似。”冒號(hào)微頷,“不妨認(rèn)為閉包就是封裝了環(huán)境變量的隱形對(duì)象的方法——通常是匿名方法。我們用一段JavaScript代碼來(lái)加深印象——”

          /* 返回函數(shù)f的近似導(dǎo)函數(shù) */

          function derivative(f)

          { // dx最好作為參數(shù)傳入,放在此處主要是為了說(shuō)明閉包的用法
                 var dx = 0.00001;     // dx越小,近似度越高
                 return function(x) { return (f(x + dx) - f(x)) / dx; };

          }

          /* 返回一個(gè)數(shù)的平方數(shù) */

          function square(x) { return x * x; }

          /* 返回一個(gè)數(shù)的雙倍數(shù) */

          function double(x) { return 2 * x; }

          /* 對(duì)任何一個(gè)不大的數(shù)值變量x(比如小于100),下列函數(shù)的返回值應(yīng)該非常接近于零 */

          function testSquareDerivative(x) { return derivative(square) (x) - double(x); }

          嘆號(hào)感到有點(diǎn)頭痛:“怎么跑出了微積分?大學(xué)學(xué)的那點(diǎn)高數(shù)早就還給老師了。”

          冒號(hào)笑著安慰他:“還給老師沒(méi)關(guān)系,我再借給你一點(diǎn):平方函數(shù)的導(dǎo)數(shù)是雙倍函數(shù)。因此,函數(shù)derivative(square)應(yīng)該很接近函數(shù)double的作用效果。作為檢驗(yàn),testSquareDerivative能將任何一個(gè)不大的數(shù)映射到近似于零的數(shù)[1]。”

          引號(hào)這下徹底明白了:“在求導(dǎo)函數(shù)derivative中,傳入的參數(shù)f和返回值都是函數(shù),這是函數(shù)作為頭等公民的特征。其中返回的匿名函數(shù)就是閉包,它附著了兩個(gè)環(huán)境變量:外層函數(shù)的傳入?yún)?shù)f和局部變量dx。”

          “完全正確!”冒號(hào)作出積極的肯定,“如果不是閉包,這兩個(gè)環(huán)境變量在derivative返回后就會(huì)失去效用。由此可見(jiàn),合理地使用閉包能使代碼更加簡(jiǎn)潔清晰,散發(fā)出函數(shù)式特有的優(yōu)雅氣質(zhì)。”

          句號(hào)有些按捺不住編程的沖動(dòng),自告奮勇:“我來(lái)具體實(shí)現(xiàn)餐館的serve方法吧。”

          得到冒號(hào)的默許,句號(hào)在黑板上寫(xiě)下——

          private void serve(Customer customer)

          {

           // 找一個(gè)空閑的接待員

          Receptionist receptionist = findReceptionist();

          receptionist.receive(customer);

          receptionist.usher(customer);

                      // 找一個(gè)空閑的服務(wù)員

          Waiter waiter = findWaiter();

          waiter.pourTea(customer);

          List<Order> orders = waiter.write(customer)       ;

          // 將菜單交給一位廚師

          Cook cook = waiter.pass(orders);

          for (Order order : orders) // 廚師照單做菜

          {

           Course course = cook.cook(order);

                      // 找一個(gè)空閑的服務(wù)員

          waiter = findWaiter();

          // 服務(wù)員上菜

          waiter.serve(customer, course);

          // 顧客開(kāi)始享用

          customer.eat(course);

          }

          // 顧客用餐完畢。。。

                // 找一個(gè)空閑的收銀員

          Cashier cashier = findCashier();

          cashier.charge(customer);

          cashier.issueInvoice(customer);

           // 找一個(gè)空閑的接待員

          receptionist = findReceptionist();

          receptionist.send(customer);

          }

          句號(hào)寫(xiě)畢又復(fù)查一遍,拍拍手上的粉筆灰,心滿意足地走下臺(tái)來(lái)。

          嘆號(hào)提意見(jiàn):“我的廚工沒(méi)派上用場(chǎng),應(yīng)該在廚師烹調(diào)前調(diào)用KitchenHandprepareFood方法。”

          問(wèn)號(hào)挑出另外的毛病:“在for循環(huán)中,廚師、服務(wù)員和顧客的行為應(yīng)該在不同的線程中,廚師不可能等服務(wù)員上完一道菜或顧客吃完一道菜后才做下一道。”

          “可能更復(fù)雜呢!”逗號(hào)也來(lái)湊熱鬧,“一位顧客點(diǎn)的幾樣菜可能分別由幾位廚師同時(shí)做,每位廚師都在不同的線程中工作。”

          引號(hào)更嚴(yán)謹(jǐn):“還應(yīng)有一個(gè)后臺(tái)線程,讓服務(wù)員(Waiter)隨時(shí)換盤(pán)(exchangePlate),讓廚工(KitchenHand)隨時(shí)洗盤(pán)(washDishes)和清潔(clean),這樣所有服務(wù)人員提供的服務(wù)都用上了。”

          句號(hào)倒抽涼氣:“估不到漏洞這么多,并發(fā)式真是無(wú)處不在啊。”

          冒號(hào)繼續(xù)點(diǎn)撥:“換盤(pán)子有兩種方式:一種是服務(wù)員主動(dòng)換,一種是客人要求換。前者是輪詢,后者是通知。”

          “哦,事件驅(qū)動(dòng)式!”句號(hào)迅即反應(yīng)過(guò)來(lái),“客人是事件源,服務(wù)員是事件處理器,客人不定期地招手呼喚是在發(fā)表事件以通知服務(wù)員。客人與服務(wù)員是多對(duì)多的松耦合關(guān)系。”

          冒號(hào)點(diǎn)點(diǎn)頭,又指著引號(hào):“剛才有人不滿你的大廚職責(zé)過(guò)于簡(jiǎn)單,現(xiàn)在你來(lái)實(shí)現(xiàn)一下,也好顯顯技術(shù)含量。”

          引號(hào)在臺(tái)上摸了半天頭,編出一段代碼——

          Class Cook

          {

          public Course cook(Order order)

          {

           // 根據(jù)菜單查食譜

          Recipe recipe = lookupRecipe(order);

          // 找到食譜的烹調(diào)步驟

          List<Instruction> instructions = recipe.getInstructions();

          for (Instruction instruction : instructions)

          {

              follow(instruction); // 按食譜的指令操作

          }

          }

          }

          “堂堂大廚原來(lái)是靠查食譜做菜的。”逗號(hào)揶揄道。

          引號(hào)為難地說(shuō):“這不是在編程嘛,好端端的人腦,不得不去模擬電腦,完全搞倒了。”

          “要設(shè)計(jì)會(huì)烹調(diào)的機(jī)器人,興許還真得這樣呢。”冒號(hào)笑道,“不過(guò)由于各種菜式組合繁多,如果每種菜都配菜譜未免太龐雜,如何精簡(jiǎn)呢?”

          句號(hào)建議:“菜式成千上萬(wàn),烹調(diào)技法相對(duì)少許多,不妨以技法為主線。”

          “好主意!”冒號(hào)挑起大拇指,“如果把待加工的菜看作數(shù)據(jù),技法看作算法,將數(shù)據(jù)與算法分離,以算法為中心,那是什么范式?”

          泛型式!”大家異口同聲。

           “至此我們已涉及了過(guò)程式、對(duì)象式、并發(fā)式、函數(shù)式、事件驅(qū)動(dòng)式和泛型式。”引號(hào)扳著手指算著,“還差邏輯式、元編程和切面式了。”

          冒號(hào)把目光轉(zhuǎn)向逗號(hào):“寫(xiě)菜單并不容易,如果客人不直接點(diǎn)菜,你的服務(wù)員如何向他推薦?”

          逗號(hào)答:“最簡(jiǎn)單的方法是報(bào)菜名,并一一詢問(wèn)客人。”

          冒號(hào)皺眉:“這樣你是簡(jiǎn)單了:一個(gè)迭代就完事,可客人也該發(fā)火了。”

          逗號(hào)趕緊修正:“先詢問(wèn)客人的口味、忌諱等等,再向他建議一些菜式。”

          “這還差不多。”冒號(hào)眉頭舒展開(kāi)來(lái),“考慮到客人的口味、忌諱等各有不同,餐館的菜單也隨時(shí)可能變化,如果把這些都硬編碼(hardcode),再加上層層疊疊的if-else語(yǔ)句,代碼將成為懶婆娘的裹腳——又臭又長(zhǎng)又難維護(hù)。”

          引號(hào)提議:“可以把這些信息預(yù)先存入數(shù)據(jù)庫(kù),屆時(shí)用SQL查詢。”

          “想法很好,只是有一點(diǎn)難度。”冒號(hào)提醒道, “這些信息并非簡(jiǎn)單的對(duì)應(yīng)關(guān)系,包含一些邏輯推理,甚至需要一些模糊判斷。”

          句號(hào)一拍大腿:“前面不是提到領(lǐng)域特定語(yǔ)言DSL嗎?將所有規(guī)則用自定義的DSL編寫(xiě),再利用元編程轉(zhuǎn)換成CJava之類(lèi)的通用語(yǔ)言,不是很好嗎?”

          “棒極了!”冒號(hào)不吝贊詞,“不過(guò)還有一種思路。我們可以搜集餐館的菜式、顧客口味、忌諱以及各種菜與口味、忌諱之間的關(guān)系等等一系列事實(shí)和規(guī)則,用規(guī)則語(yǔ)言Rule Language)來(lái)描述,通過(guò)規(guī)則引擎Rule Engine)來(lái)導(dǎo)出符合顧客需求的菜肴。這種方式將業(yè)務(wù)規(guī)則與應(yīng)用程序分離、將知識(shí)表示與邏輯實(shí)現(xiàn)分離,是SoC原理的一種應(yīng)用,同時(shí)也是一種邏輯式編程。”

          問(wèn)號(hào)關(guān)心地問(wèn):“這些規(guī)則引擎與Java程序兼容嗎?”

          冒號(hào)回答:“不少規(guī)則引擎用Java實(shí)現(xiàn)或?qū)?/span>Java平臺(tái)設(shè)計(jì),如JessDroolsJLisaJRules等,另外Sun還發(fā)布了javax.rules API (JSR 94)以統(tǒng)一對(duì)各類(lèi)引擎的訪問(wèn)接口。”

          引號(hào)頗感意外:“既然是邏輯式編程,為什么不采用代表語(yǔ)言Prolog呢?”

          冒號(hào)準(zhǔn)備了一大段理由等著他:“剛才提到的規(guī)則引擎都是基于Rete算法[2]的,主要采用數(shù)據(jù)驅(qū)動(dòng)的(data-driven正向推理forward chaining)法,而Prolog引擎采用目標(biāo)驅(qū)動(dòng)的(goal-driven逆向推理backward chaining)法。正向推理自底向上,利用推理規(guī)則從已有的事實(shí)數(shù)據(jù)推出更多的數(shù)據(jù),直到達(dá)成目標(biāo);逆向推理正相反,自頂向下,從目標(biāo)出發(fā)尋找滿足結(jié)論的事實(shí)[3]。相比而言,正向推理適合針對(duì)不同輸入作出不同反應(yīng),而逆向推理適合回答查詢。現(xiàn)在是服務(wù)員根據(jù)客人的喜好提建議,當(dāng)然用正向推理更合適。再說(shuō)這類(lèi)引擎與Java的集成更加方便,因此我們沒(méi)有選擇Prolog。”

          講到此處,每個(gè)人都意識(shí)到,只剩下最后一個(gè)范式了。

          冒號(hào)提出一個(gè)新問(wèn)題:“假如餐館經(jīng)理接到顧客投訴,反映服務(wù)人員態(tài)度不好,衛(wèi)生狀況也不理想,應(yīng)該怎么辦?”

          問(wèn)號(hào)搶先說(shuō):“首先我的接待員在迎客(receive)時(shí)要笑容可掬地對(duì)顧客說(shuō):‘歡迎光臨!’,在送客(send)時(shí)要對(duì)顧客鞠躬:‘請(qǐng)慢走,歡迎下次再來(lái)’”

          逗號(hào)接著說(shuō):“我的服務(wù)員在上完菜后應(yīng)對(duì)客人說(shuō):‘請(qǐng)慢用’,句號(hào)的收銀員也應(yīng)加些禮貌用語(yǔ),讓人家高高興興地掏錢(qián)。”

          句號(hào)補(bǔ)充道:“服務(wù)員在上菜(serve)前、廚師在烹飪(cook)前應(yīng)洗手,廚工在洗碗(washDishes)后應(yīng)對(duì)餐具消毒。”

          冒號(hào)緊接著問(wèn):“如果餐館對(duì)禮貌規(guī)范或衛(wèi)生標(biāo)準(zhǔn)做修改,必然要牽扯不同類(lèi)中的不同的方法,維護(hù)起來(lái)很不方便,怎樣才能有效地解決這個(gè)問(wèn)題呢?”

          答案已經(jīng)昭然若揭了。

          冒號(hào)干脆自問(wèn)自答:“不錯(cuò),正是用切面式編程。只要?jiǎng)?chuàng)立兩個(gè)AspectEtiquetteSanitation,分別負(fù)責(zé)禮貌規(guī)范和衛(wèi)生標(biāo)準(zhǔn)方面的事務(wù)。一旦某一方面的要求發(fā)生變化,比如餐館來(lái)了外賓,或者碰上非典或禽流感,只需在相應(yīng)的Aspect模塊中作調(diào)整:將禮貌用語(yǔ)換成英語(yǔ)或者提高衛(wèi)生標(biāo)準(zhǔn)等等。如果采用runtime AOP,甚至還可在運(yùn)行期選擇激活或禁用這些Aspect。”

          下面開(kāi)始有些騷動(dòng),大伙早已腦中滿滿而腹中空空,有點(diǎn)頭重腳輕了。

          冒號(hào)見(jiàn)狀,遂發(fā)出激動(dòng)人心的號(hào)召:“今天的課到此結(jié)束,讓我們從虛擬的餐館中走出,到真實(shí)的餐館中去吧!”

          眾人齊聲歡呼。


            插語(yǔ)


          [1] 若輸入數(shù)過(guò)大,則需要設(shè)定更小的dx。此外,還可能產(chǎn)生計(jì)算溢出。

          [2] Rete算法是一種高效的模式匹配算法,用于實(shí)現(xiàn)規(guī)則生成系統(tǒng)(production rule system

          [3] 用邏輯的語(yǔ)言來(lái)說(shuō),正向推理順著從前件(即if語(yǔ)句)到后件(即then語(yǔ)句)的方向,逆向推理順著從后件到前件的方向。

            
           總結(jié)


          l        閉包是一種能保留當(dāng)初創(chuàng)建時(shí)的環(huán)境變量的函數(shù)。它通常以匿名的方式存在,多用于函數(shù)式編程中,能使代碼更加簡(jiǎn)潔清晰。Java中的匿名類(lèi)可以看作OO化的閉包形式。

          l        JessDroolsJLisaJRules等規(guī)則引擎主要基于正向推理,能無(wú)縫地與Java平臺(tái)集成。它們提供了邏輯式編程環(huán)境,能有效地將業(yè)務(wù)規(guī)則從應(yīng)用程序中分離出來(lái),提高了軟件的靈活性和可維護(hù)性。

          l        每種編程范式都能在生活中找到它的應(yīng)用,它們本來(lái)就是人類(lèi)思維方式的投影。

            

           “”參考


          [1] WikipediaClosure (computer science)http://en.wikipedia.org/wiki/Closure_(computer_science)

          [2] Ernest Friedman-HillJess 7.1p2 manualhttp://www.jessrules.com/jess/docs/Jess71p2.pdf

          [3] Mark Proctor等.Drools Documentationhttp://downloads.jboss.com/drools/docs/4.0.7.19894.GA/html_single/index.html

           

          課后思考

          l      同樣一個(gè)問(wèn)題用不同的語(yǔ)言來(lái)編程,代碼可能會(huì)有極大的差異。你認(rèn)為這種差異的主要根源是語(yǔ)言還是范式?

          l      認(rèn)真研究本課中的編程范式匯總表,并補(bǔ)充新的內(nèi)容,如各范式的關(guān)鍵詞、理論基礎(chǔ)、最佳實(shí)踐、注意事項(xiàng)等等。

          l      掌握編程范式對(duì)語(yǔ)言學(xué)習(xí)和編程設(shè)計(jì)有何實(shí)際意義?

          posted on 2008-12-21 23:18 鄭暉 閱讀(3115) 評(píng)論(1)  編輯  收藏 所屬分類(lèi): 冒號(hào)課堂

          評(píng)論

          # re: 冒號(hào)課堂§4.4:情景范式 2008-12-22 09:52 貓團(tuán)長(zhǎng)

          實(shí)在是精辟,頂!  回復(fù)  更多評(píng)論   

          導(dǎo)航

          統(tǒng)計(jì)

          公告

          博客搬家:http://blog.zhenghui.org
          《冒號(hào)課堂》一書(shū)于2009年10月上市,詳情請(qǐng)見(jiàn)
          冒號(hào)課堂

          留言簿(17)

          隨筆分類(lèi)(61)

          隨筆檔案(61)

          文章分類(lèi)(1)

          文章檔案(1)

          最新隨筆

          積分與排名

          最新評(píng)論

          閱讀排行榜

          評(píng)論排行榜

          主站蜘蛛池模板: 抚远县| 招远市| 会昌县| 延安市| 乃东县| 建德市| 广灵县| 讷河市| 定兴县| 巴东县| 台南市| 巴林右旗| 红桥区| 平原县| 湘西| 太仆寺旗| 新宾| 巴楚县| 长海县| 建宁县| 耒阳市| 永善县| 始兴县| 旺苍县| 娄底市| 临海市| 滁州市| 鄯善县| 华池县| 冕宁县| 新郑市| 扬中市| 宜宾市| 新安县| 沈阳市| 德州市| 静安区| 武汉市| 黎川县| 古浪县| 吉林市|