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

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

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

      享受代碼,享受人生

      SOA is an integration solution. SOA is message oriented first.
      The Key character of SOA is loosely coupled. SOA is enriched
      by creating composite apps.
        博客園  :: 首頁  :: 新隨筆  :: 聯系 :: 訂閱 訂閱  :: 管理

      Double Dispatch And Visitor Pattern

      Posted on 2006-02-03 16:45  idior  閱讀(4126)  評論(5)    收藏  舉報

                                           

      1 Override VS. Overload

            多態可以說是面向對象世界中一件鋒利的武器, 封裝變化是它的能力的體現。但是你聽說過幾種多態?

      Simple Polymorphism the object whose method is called is decided run-time.
          multi- polymorphism the object which method is called  is decided upon the type of the argument

            如果你對這兩句描述不是很清楚, 那你知道overrideoverload嗎?Simple Polymorphism 就意味使用了override, multi- polymorphism則意味著使用了overload

      前者可能你比較熟悉,后者呢?兩者又有什么不同?什么情況下我們會需要后者呢?你見過它們同時出現嗎?

      多態是用于封裝變化的,比如常見的那個Shape Draw的例子。Client不用考慮具體是哪個Shape,通過多態自然能調用到相應的那個ShapeDraw方法(whose method)。但是這時我們只有一個變化的對象――Shape 如果畫的地方也變呢?比如我可以畫在屏幕上, 也可以畫到打印機上。現在我們有兩個同時會變的因素, 那么Draw方法又通過什么來實現封裝變化呢? Simple Polymorphism 顯然是不夠用了,multi- polymorphism 自然也該出場了。

      就從一個游戲開始吧,在這個游戲中有一個怪物開門的場景。怪物有很多種,本游戲的出場人物包括了矮人和泰坦,門也有兩種 :一種普通的木頭門, 還有就是很重的鐵門。

      現在怪物和門登場了

      interface Monster    {}

          class Drawf : Monster    {} 

          class Giant : Monster    {}

          class Door
          {
              public virtual void OpenBy(Monster monster)
              {
                  Console.WriteLine("Who are u?");
              }

              public virtual void OpenBy(Drawf dwarf)
              {
                  Console.WriteLine("It's slowly opened");
              }

              public virtual void OpenBy(Giant giant)
              {
                  Console.WriteLine("It's just easily broken...Crasp!");
              }
          }

          class HeavyDoor : Door
          {
              public override void OpenBy(Drawf dwarf)
              {
                  Console.WriteLine("It won't open");
              } 

              public override void OpenBy(Giant giant)
              {
                  Console.WriteLine("It's slowly opened");
              }
          } 

      這里為了同時封裝兩種變化(怪物和門),我也同時使用了override overload

      接著怪物開始開門了

          class Game
          {
              static void Main()
              {
                  Door ironDoor = new HeavyDoor();
                  ironDoor.OpenBy(new Drawf());
                  ironDoor.OpenBy(new Giant());
              }
          }

          答案也很明顯

       

      這個例子同時應用了兩種多態, 但是卻只體現了第一種多態封裝變化的效果!如何將兩者都體現出來?看下面的測試

      class Game
          {
              static void Main()
              {

                  Door ironDoor = new HeavyDoor();
                  List<Monster> monsters = new List<Monster>();
                  monsters.Add(new Drawf());
                  monsters.Add(new Giant());

                  foreach (Monster m in monsters)
                      ironDoor.OpenBy(m);
                }
            } 

      現在你能猜到結果嗎?仔細想想別急著看答案 

            很正常?Ok. 你可以直接去看下一節的內容了,如果猜錯了請先復習一下下面的基礎知識吧.

      你肯定聽說過所謂的動態綁定,通常意義上的多態也就是通過它實現的,簡而言之――the object whose method is called is decided run-time . 重點就在于這個run-time . 而第二種多態――the object which method is called  is decided upon the type of the argument 這里面可沒有出現run-time 倒不是說它不支持,而是不一定,不過在c++, javac# 中都不支持。 現在你可以理解為什么前面的答案出乎你的意料了。因為后者方法是靜態綁定的, 也就是在編譯期就確定了將要執行哪個Draw方法,而在編譯期,編譯器顯然只能將monsters集合中的對象判斷為Monster類型,從而去執行 void OpenBy(Monster monster)方法。

      2 Visitor Pattern without Double Dispatch

              通過上一節的例子和解釋, 你應該對override, overload 以及他們各自的綁定機制――動態綁定和靜態綁定有所了解。

              接下來看一個更具實際意義的例子。假設我想做一個計算器,那么肯定要先建立一個表達式系統。 

       abstract class Expression
      {
          public abstract int Evaluate();
      }

          class ConstantExpression : Expression
          {       
              
      int constant;
              public override int Evaluate()
              {
                  return constant;
              }
          }

          class SumExpression : Expression
          {
              Expression left, right;
              public override int Evaluate()
              {
                  return left.Evaluate() + right.Evaluate();
              }
          } 

      這里利用多態很好的實現了表達式計算的任務但是把計算的功能放在表達式中并不是一個良好的設計,隨著表達式的類型越來越復雜,可能我們需要對表達式進行語法分析,進行類型檢查, 設置判斷表達式中有多少個常量,多少個變量。如果把這些功能都放在表達式中,一方面不符合責任分離的原則,二來一旦有了新的功能需求我們就要修改所有的表達式對象,維護的惡夢就這樣開始了。

           于是我就想到了用Visitor模式將計算的功能從Express類中分離出來。(將過多沒有密切聯系的功能從原來的對象中脫離出來,避免對象過于龐大,這是使用Visitor模式的最重要的原因)。下面是代碼實現,請耐心看完。      

       abstract class Expression { } 

          class ConstantExpression : Expression
          {
              private int constant;
              public int Constant
              {
                  get { return constant; }
              }

              public ConstantExpression(int con)
              {
                  constant = con;
              }
          } 

          class SumExpression : Expression
          {
              private Expression left, right;
              public Expression Right
              {
                  get { return right; }
              }
              public Expression Left
              {
                  get { return left; }
              }

              public SumExpression(Expression left, Expression right)
              {
                  this.left = left;
                  this.right = right;
              }
          }

       
         class EvaluateVisitor
          {
              public int Visit(ConstantExpression e)
              {
                  return e.Constant;
              }
              public int Visit(SumExpression e)
              {
                  return Visit(e.Left) + Visit(e.Right);
              }
          } 

          class Program
          {
              static void Main()
              {
                  ConstantExpression constExp = new ConstantExpression(10); 
                  SumExpression sumExp = new SumExpression(new ConstantExpression(1),
                                                           new ConstantExpression(1));

                  EvaluateVisitor evalVisitor = new EvaluateVisitor();
                  Console.WriteLine(evalVisitor.Visit(constExp));
                  Console.WriteLine(evalVisitor.Visit(sumExp));
              }
           }
       

      看完上面的代碼,可能很多人會有疑問了。 你這里用的是什么Visitor模式?Accept方法呢?IVisitor接口呢? 怎么Visit方法還有返回值?怎么和《Design Pattern》上的Visitor模式完全不是一回事?

      為什么要和書上的一樣呢?你難道沒發現以上的疑問都體現了這個版本的優點?沒有Accpet方法意味著在最初的設計中我根本不需要為以后是否需要使用Visitor模式做考慮。沒有IVisitor接口,意味著我可以隨意的定義我的Visit方法,而不需要一個統一的形式,比如這里為了計算方便我讓Visit方法有了返回值。既然這個版本的Visitor模式這么好,怎么Gof沒有想到? 呵呵,露餡了,因為上面的代碼根本無法通過編譯       

             class EvaluateVisitor
          {
              public int Visit(ConstantExpression e)
              {
                  return e.Constant;
              }
              public int Visit(SumExpression e)
              {
                  return Visit(e.Left) + Visit(e.Right);
              }
          } 

      聯系第一節介紹的內容,你就會發現盡管e.Left在運行期是ConstantExpression類型,但是由于Overload的方法是靜態綁定的, 而在編譯期e.LeftExpress類型, 但是我們根本沒有提供Visit(Expression e)這樣的方法, 編譯自然出錯了。       

       3 Visitor Pattern with Double Dispatch       

             回過頭去看看傳統的Visitor模式又是什么樣子的呢?

      abstract class Expression
      {
          public abstract void Accept(Visitor v);
      } 

      class ConstantExpression : Expression
      {
          private int constant;
          public int Constant
          {
              get { return constant; }
          }

          public ConstantExpression(int con)
          {
              constant = con;
          }

          public override void Accept(Visitor v)
          {
              v.Visit(this);
          }
      } 

      class SumExpression : Expression
      {
          private Expression left, right;
          public Expression Right
          {
              get { return right; }
          } 

          public Expression Left
          {
              get { return left; }
          }

          public SumExpression(Expression left, Expression right)
          {
              this.left = left;
              this.right = right;
          } 

          public override void Accept(Visitor v)
          {
              v.Visit(this);
          }
      }

       

      interface Visitor
      {
          void Visit(ConstantExpression e);
          void Visit(SumExpression e);
      }

      class EvaluateVisitor : Visitor
      {
          private int result;
          public int Result { get { return result; } }

          public void Visit(ConstantExpression e)
          {
              result=e.Constant;
          }

          public void Visit(SumExpression e)
          {
              e.Left.Accept(this);
              int lefeRe = this.result;
              e.Right.Accept(this);
              int rightRe = this.result;
              result = lefeRe + rightRe;
          }
      }

      class Program
      {
          static void Main()
          {
              ConstantExpression constExp = new ConstantExpression(10);
              SumExpression sumExp = new SumExpression(new ConstantExpression(1),
                                                       new ConstantExpression(1)); 

              EvaluateVisitor evalVisitor = new EvaluateVisitor();
              constExp.Accept(evalVisitor);
              Console.WriteLine(evalVisitor.Result);
              sumExp.Accept(evalVisitor);
              Console.WriteLine(evalVisitor.Result);
          }
      }

          可以看出這張圖和前者相比,復雜了許多。但是只有這樣我們才能在C#這種不直接支持Double Dispatch的語言中實現Visitor模式。

             怎么解決的呢? 道理很簡單就是用Twice Single Dispatch來模擬Double Dispatch。最能體現Twice Single Dispatch的代碼如下:
             public override void Accept(Visitor v)
          {
              v.Visit(this);
          }

       其一般形式為:
          public void MethodA(A a)
          {
              a.MethodB(this);
          }     

             其實說到底,不支持Double Dispatch就是由于不支持方法參數的動態綁定, 那我們就通過兩次的O虛方法的動態綁定來模擬它。所以 a 又從方法參數變成了虛方法的擁有者,并把this作為參數傳入。

             明白了以上的道理,你也就知道為什么完全同樣的Accpet方法沒有被提到它們的基類中――-因為方法參數的類型是在編譯期決定的。 

             看到了傳統Visitor模式的解決思路,對于文章一開始的小游戲所引起的問題也就不難解決了。      

      4 Visitor Pattern with Reflection

              
             
          再來看看第二節的模型,實在是很漂亮,讓我不忍放棄。Gof 也想不出什么好的辦法,只能無奈的采用了第三節的復雜模型。 不過,你記得嗎?《Design Pattern》那本書可是十年前的作品。十年前可沒有什么元數據,自然也沒有Reflection

      通過反射我完全可以在運行期從函數參數中找回失去的類型信息。

      我只要在第二節的EvaluateVisitor類中添加如下的一個方法,就萬事告吉了。

       public int Visit(Expression e)
           {
                  Type[] types = new Type[] { e.GetType() };
                  MethodInfo mi = this.GetType().GetMethod("Visit", types);
                  if (mi==null)
                      throw new Exception("UnSupported!");
                  else
                      return (int)mi.Invoke(this,new object[]{e});
           }

         這個方法我個人是比較滿意了,你覺得呢? 在寫sample的時候,我總覺得泛型也應該能解決這個問題,不過在寫完后也沒想到一個比較方便的解決方案。可能是對泛型了解的還不夠,裝配腦袋來試試?

      參考資料:

      文章開始的Game的各種版本實現
      Generic Double Dispatch Engine
      Visitor模式全解

      主站蜘蛛池模板: 亚洲中文字幕一区二区| 亚洲中文字幕人妻系列| 高清在线一区二区三区视频| 亚洲愉拍一区二区三区| 国产日韩一区二区三区在线观看| 久久精品午夜视频| 午夜福利yw在线观看2020| 成人亚洲a片v一区二区三区动漫 | 日韩精品一区二区三免费| 亚洲av无码之国产精品网址蜜芽| 国产视色精品亚洲一区二区| 使劲快高潮了国语对白在线| 亚洲人成人无码www| 久热这里有精品视频在线| 欧洲亚洲国内老熟女超碰| 男女爽爽无遮挡午夜视频| 无码伊人久久大杳蕉中文无码| 巩义市| 和艳妇在厨房好爽在线观看| 4hu44四虎www在线影院麻豆| 亚洲永久精品日韩成人av| caoporn成人免费公开| 中文字幕精品久久久久人妻红杏1| 韩国无码AV片午夜福利| 人人妻人人澡人人爽人人精品av| 亚洲av二区三区在线| 亚洲成a人片77777kkkk| 国产伦精品一区二区三区妓女下载| 国产自产对白一区| 久热这里只有精品蜜臀av| 好男人视频在线播放| 亚洲国产成人综合精品| 国产在线观看网址不卡一区| 日韩人妻中文字幕精品| 亚洲a∨无码一区二区三区| 懂色AV| 国产不卡在线一区二区| 日本一卡2卡3卡四卡精品网站| 午夜毛片不卡免费观看视频| 少妇真人直播免费视频| 中文字幕在线亚洲精品|