<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      對象的消息模型

      話題從下面這段C++程序說起,你認為它可以順利執行嗎?

      //C++
      class A { 
      public: 
          void Hello(const std::string& name) { 
              std::cout << "hello " << name; 
          } 
      };
      int main(int argc, char** argv) { 
          A* pa = NULL;  //!! 
          pa->Hello("world"); 
          return 0; 
      }
      

      試試的確可以順利運行輸出hello world,奇怪嗎?其實并不奇怪,根據C++對象模型,類的非虛方法并不會存在于對象內存布局中,實際上編譯器是把Hello方法轉化成了類似這樣的全局函數:

      void A_Hello_xxx(A * const this, const std::string& name) {
          std::cout << “hello “ << name;
      }
      

      對象指針其實是作為第一個參數被隱式傳遞的,pa->Hello(“world”)實際上是調用的A_Hello_xxx(pa, “world”),而恰好A_Hello_xxx內部沒有使用pa,所以這段代碼得以順利運行。

      對象的消息模型

      如果是研究C++對象模型,上面的討論可以到此為止,不過這里我想從另一個角度來繼續探討這個問題。OOP的先驅人物Alan Kay在總結Smalltalk的OO特征時強調:

      Smalltalk is not only NOT its syntax or the class library, it is not even about classes. I'm sorry that I long ago coined the term "objects" for this topic because it gets many people to focus on the lesser idea. The big idea is "messaging".

      也就是說相比類和對象的概念來講,他認為對象交互的消息模型是OOP更為本質的特征,因為消息關注的是對象間的接口和交互,在構建大的系統的時候重要的不是對象的內部狀態,而是它們的交互。根據消息模型,牛.吃(草) 的語義是發送一條消息給“牛”,消息的類型是“吃”,消息的內容是“草”。如果按照嚴格的消息模型,那么上面那段C++代碼應解釋為向一個NULL對象發送Hello消息,這顯然是不應該順利執行的。類似的代碼如果是在Java或C#中則會拋出空引用異常,所以Java和C#的設計更符合消息模型。

      不過,Java和C#中也并非完全符合消息模型,來看一個經典的封裝問題:

      //C#
      public class Account { 
          private int _amount;
          public void Transfer(Account acc, int delta) { 
              acc._amount += delta; 
              this._amount -= delta; 
          }
          … 
      }
      

      上面定義了一個Account類,問題在于為什么在這個類的Transfer方法中可以直接訪問另一個對象acc的私有成員_amount呢?這是不是有破壞封裝的嫌疑呢?這個問題經典的答案是:并不破壞封裝,封裝是劃分了基于類的靜態的代碼邊界,使得類的private代碼修改不影響外界,而不是對于動態對象的保護。這個解釋當然是合理的,不過正如上面C++代碼的解釋屬于C++對象模型范疇,這個解釋則屬于基于類的靜態類型OOP語言的范疇。消息模型強調了對象內部狀態的保護,只能通過消息改變其狀態,而對象內部是否真的具有_amout這樣一個私有成員對其他任何對象(即使同類對象)都是未知的。

      如果要嚴格遵守消息模型實現對象內部狀態的保護應該怎么做呢?我們來看一個例子,定義一個集合類,包括:1.集合對象的構造函數;2.In方法:判斷元素是否存在;3.Join方法:對兩個集合做交集;4.Union方法:對兩個集合做并集。下面是一種Javascript實現:

      //Javascript
      //集合類Set的構造函數
      function Set() { 
          var _elements = arguments;
          //In方法:判斷元素e是否在集合中 
          this.In = function(e) { 
              for (var i = 0; i < _elements.length; ++i) { 
                  if (_elements[i] == e) return true; 
              } 
              return false; 
          }; 
      }
      
      //Join方法:對兩個集合求交集
      Set.prototype.Join = function(s2) { 
          var s1 = this; 
          var s = new Set(); 
          s.In = function(e) { return s1.In(e) && s2.In(e); } 
          return s; 
      };
      
      //Union方法:對兩個集合求并集
      Set.prototype.Union = function(s2) { 
          var s1 = this; 
          var s = new Set(); 
          s.In = function(e) { return s1.In(e) || s2.In(e); } 
          return s; 
      };
      
      var s1 = new Set(1, 2, 3, 4, 5); 
      var s2 = new Set(2, 3, 4, 5, 6); 
      var s3 = new Set(3, 4, 5, 6, 7); 
      assert(false == s1.Join(s2).Join(s3).In(2)); 
      assert(true == s1.Join(s2).Uion(s3).In(7));
      

      如果是在靜態類型OOP語言中,要實現集合類的Join或Union,我們多半會像上面Account的例子一樣直接對s2內部的_elements進行操作,而上面這段Javascript定義的Set關于對象s2的訪問完全是符合消息模型的基于接口的訪問。要實現消息模型Javascript的prototype機制并非必須的,真正的關鍵在于函數式的高階函數和閉包特性。從這個例子我們也可以體會到函數式的優點不僅在于無副作用,函數的可組合性也是函數式編程強大的原因。

      Method Missing

      接下來我們還要進行深度歷險,讓我們思考一下如果發送一條對象不能識別的消息會怎樣?這種情況在C++、Java、C#等靜態語言中會得到一個方法未定義的編譯錯誤,如果是在Javascript中則會產生運行時異常。比如,s1.count()會產生一個運行時異常:Object # has no method 'count'。

      在靜態語言這個問題很少受到重視,但在動態語言中卻大有文章,來看下面的例子:

      //Ruby
      builder = Builder::XmlMarkup.new 
      xml = builder.books {|b| 
          b.book :isbn => "14134" do 
              b.title "Revelation Space" 
              b.author "Alastair Reynolds" 
          end
          b.book :isbn => "53534" do 
              b.title "Accelerando" 
              b.author "Charles Stross" 
          end 
      }
      

      上面這段很DSL的Ruby代碼創建了這樣一個XML文件對象:

      <books> 
          <book isbn="14134"> 
              <title>Revelation Space</title> 
              <author>Alastair Reynolds</author> 
          </book> 
          <book isbn="53534"> 
              <title>Accelerando</title> 
              <author>Charles Stross</author> 
          </book> 
      </books>
      

      ? builder.books, b.book, b.title都是對象方法調用,由于XML的元素名是任意的,所以不可能事先定義這些方法,類似的代碼如果是在Javascript中就是no method異常。那為什么上面的Ruby代碼可以正確執行呢?其實只要理解了消息模型就很容易想明白,只需要定義一個通用的消息處理方法,所有未明確定義的消息都交給它來處理就行了,這就是所謂的Method Missing模式:

      class Foo 
          def method_missing(method, *args, &block)
              … 
          end 
      end
      

      Method Missing除了對實現DSL很重要外,還可用于產生更好地調試和錯誤信息,把參數嵌入到方法名中等場合。目前,Ruby、Python、Groovy幾種語言對Method Missing都有很好的支持,甚至在C# 4.0中也可以利用動態特性實現。

      總結

      本文主要介紹了對象的消息模型的特征,并比較了C++對象模型,Java、C#等基于類的靜態語言中的對象模型與嚴格消息模型的差異,最后探討了Method Missing相關話題。

      參考

      Alan Kays Definition Of Object Oriented
      OOP The Good Parts: Message Passing, Duck Typing, Object Composition, and not Inheritance
      Patterns of Method Missing
      Fun With Method Missing and C# 4
      《冒號課堂 - 編程范式與OOP思想》

       

      posted on 2011-08-14 17:28  Todd Wei  閱讀(7782)  評論(4)    收藏  舉報

      主站蜘蛛池模板: 亚洲天堂成人一区二区三区| 色一情一区二区三区四区| 久久亚洲精品中文字幕波多野结衣| 国产午夜91福利一区二区| 亚洲欧美成人一区二区在线电影| 99久久亚洲综合精品成人网| 色丁香一区二区黑人巨大| 蜜臀av日韩精品一区二区| 久久av色欲av久久蜜桃网| 亚洲日韩亚洲另类激情文学| 青青国产揄拍视频| av无码av无码专区| 国产午夜伦伦午夜伦无码| 国产超高清麻豆精品传媒麻豆精品| 亚洲一线二线三线品牌精华液久久久| 成年女人碰碰碰视频播放| 好紧好滑好湿好爽免费视频| 国产成人av一区二区三| 国产精品午夜福利合集| 777天堂麻豆爱综合视频| 无码免费大香伊蕉在人线国产| √天堂资源地址在线官网| 国内自拍偷拍福利视频看看| 国产成人一区二区三区免费| 最近免费中文字幕大全免费版视频 | 日韩精品一区二区三区激情| 国产中文字幕日韩精品| 国产成人无码网站| 最新亚洲人成网站在线影院| 久久国产成人精品国产成人亚洲| 日韩淫片毛片视频免费看| 国产麻花豆剧传媒精品mv在线| 亚洲av成人三区国产精品| 国产综合久久亚洲综合| 亚洲国产欧美一区二区好看电影| 国产福利永久在线视频无毒不卡| 无遮高潮国产免费观看| 变态另类视频一区二区三区| 亚洲成人av在线资源| 国产精品久久久久久福利| 亚洲精品久久国产高清小说|