日本综合一区二区|亚洲中文天堂综合|日韩欧美自拍一区|男女精品天堂一区|欧美自拍第6页亚洲成人精品一区|亚洲黄色天堂一区二区成人|超碰91偷拍第一页|日韩av夜夜嗨中文字幕|久久蜜综合视频官网|精美人妻一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營銷解決方案
Java的雙重分發(fā)與Visitor模式

雙重分發(fā)(Double Dispatch)

成都創(chuàng)新互聯(lián)公司公司2013年成立,先為永城等服務(wù)建站,永城等地企業(yè),進(jìn)行企業(yè)商務(wù)咨詢服務(wù)。為永城企業(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問題。

什么是雙重分發(fā)?

談起面向?qū)ο蟮某绦蛟O(shè)計(jì)時(shí),常說起的面向?qū)ο蟮摹付鄳B(tài)」,其中關(guān)于多態(tài),經(jīng)常有一個(gè)說法是「父類引用指向子類對象」。

這種父類的引用指向子類對象的寫法類似下面這種:

 
 
 
 
  1. Animal animal = new Dog(); 
  2. animal.bark(); 

另一種常用的形式是

 
 
 
 
  1.  public class Keeper { 
  2.   
  3.      public void say(Animal a) { 
  4.          System.out.println("Animal say"); 
  5.      } 
  6.   
  7.      public void say(Dog dog) { 
  8.          System.out.println("dog say"); 
  9.      } 
  10. Animal animal = new Animal(); 
  11. Animal dog = new Dog(); 
  12. Keeper keeper = new Keeper(); 
  13. keeper.say(animal); 
  14. keep.say(dog); 

那上面的keeper調(diào)用兩次say的時(shí)候,會輸出什么內(nèi)容呢?會調(diào)用到兩個(gè)不同的方法嗎?

實(shí)際上在這兩次調(diào)用的時(shí)候,都會調(diào)用到say(Animal a)這個(gè)方法。由于這些內(nèi)容在編譯期就能確實(shí)下來,這就是 Java 的 靜態(tài)分發(fā)。

從上面的圖我們看到,對于兩次調(diào)用生成的字節(jié)碼,確實(shí)都指向了say(Animal a)這個(gè)方法,運(yùn)行時(shí)直接執(zhí)行方法,輸出了對應(yīng)的內(nèi)容。

那對應(yīng)的animal.bark() 為什么最終會調(diào)用到 dog 類的方法?這是在運(yùn)行時(shí)確定具體的方法接收者的類型并執(zhí)行。這就是所謂的動態(tài)分發(fā),在運(yùn)行時(shí)確定具體的方法,實(shí)現(xiàn)面向?qū)ο蟮亩鄳B(tài)。

分發(fā)(Dispatch)

分發(fā)就是指最終確定一個(gè)要執(zhí)行的方法的過程。

對于 Java 等靜態(tài)語言來說,都是通過 單一分發(fā)(Single Dispatch)來進(jìn)行的方法執(zhí)行。

比如這樣一行代碼

 
 
 
 
  1. dog.eat(new Bone()) 

最終執(zhí)行要選擇的eat方法,只會根據(jù)dog的具體類型選擇到對應(yīng)的方法,而傳入的參數(shù)并不能影響到對應(yīng)方法的選擇,這種就是 single Dispatch

為了讓傳入的真實(shí)參數(shù),這里就是Bone來真正起到作用,就需要用到Double Dispatch或者叫做Multiple Dispatch

也就是說最終決定調(diào)用方法是哪一個(gè)的,不僅僅是方法的接收者,還受參數(shù)類型的決定。

Visitor 模式

在GoF 的設(shè)計(jì)模式中,Visitor 模式就使用到了Double Dispatch 達(dá)到了調(diào)用真實(shí)對象的目的。

對于Visitor 模式,最常用的例子是樹的遍歷。比如在處理到節(jié)點(diǎn)和樹葉時(shí)的方式有區(qū)別,此歸通過 visitor 的雙重分發(fā),實(shí)現(xiàn)對于不同的 Element ,執(zhí)行不同的內(nèi)容。

代碼類似這樣:

 
 
 
 
  1. node.accept(new ConcreateVisitor()); 
  2. leaf.accept(new ConcreateVisitor()); 

node 中的 accept方法,會將自己的真實(shí)類型再次傳遞回visitor

 
 
 
 
  1. public void accept(Visitor v) { 
  2.     v.visit(this); 

此時(shí),在visitor中,就能根據(jù)真實(shí)的類型來調(diào)用具體的方法,對應(yīng)node 和 leaf 分別有類似這樣的方法:

 
 
 
 
  1. public void visit(Node n); 
  2. public void visit(Leaf l); 

Visitor 總結(jié)起來一般是包含 visitor 接口,在visitor 接口中,包含各個(gè)即將被訪問的 Element對象的處理邏輯。在 各個(gè)Element 的具體實(shí)現(xiàn)中,再將自己的類型傳遞回visitor 進(jìn)行二次分發(fā),實(shí)現(xiàn)確切邏輯的調(diào)用。

在Tomcat中的應(yīng)用

Visitor 在Tomcat中也有應(yīng)用,典型的是解析EL表達(dá)式。

比如org.apache.el.parser.Node

這個(gè)類中包含一個(gè)accept(NodeVisitor visitor)方法

實(shí)際的 Node 類型有很多,但在真實(shí)調(diào)用的這個(gè)時(shí)候,會通過

 
 
 
 
  1. public void accept(NodeVisitor visitor) throws Exception { 
  2.         visitor.visit(this); 

將真實(shí)類型傳回visitor, vistor中會調(diào)用具體的方法,從而實(shí)現(xiàn)參數(shù)也能起到?jīng)Q定作用的功能。

 
 
 
 
  1. public void visit(Node node) throws ELException { 
  2.         if (node instanceof AstFunction) { 
  3.  
  4.             AstFunction funcNode = (AstFunction) node; 
  5.  
  6.             Method m = null; 
  7.  
  8.            } else if (xxx) { 
  9.     } 

這里一般會聲明多個(gè)visit方法,然后上面的visit(this)會直接定位到目標(biāo)方法上。

以上就是 Java 中的各類分發(fā),以及 visitor這種模式通過模式的形式來實(shí)現(xiàn)雙重分發(fā)的效果。

【本文為專欄作者“侯樹成”的原創(chuàng)稿件,轉(zhuǎn)載請通過作者微信公眾號『Tomcat那些事兒』獲取授權(quán)】

戳這里,看該作者更多好文


本文題目:Java的雙重分發(fā)與Visitor模式
鏈接地址:http://www.dlmjj.cn/article/dheides.html