国产午夜成人免费看片无遮挡_日本免费xxxx色视频_免费人成网上在线观看_黄网址在线永久免费观看

當(dāng)前位置:雨林木風(fēng)下載站 > 技術(shù)開(kāi)發(fā)教程 > 詳細(xì)頁(yè)面

Java Tip: 用Reflection完成Visitor模式(轉(zhuǎn))

Java Tip: 用Reflection完成Visitor模式(轉(zhuǎn))

更新時(shí)間:2022-05-01 文章作者:未知 信息來(lái)源:網(wǎng)絡(luò) 閱讀次數(shù):

Java Tip: 用Reflection實(shí)現(xiàn)Visitor模式

概述

Visitor模式的常用之處在于,它將對(duì)象集合的結(jié)構(gòu)和對(duì)集合所執(zhí)行的操作分離開(kāi)來(lái)。例如,它可以將一個(gè)編譯器中的分析邏輯和代碼生成邏輯分離開(kāi)來(lái)。有了這樣的分離,想使用不同的代碼生成器就會(huì)很容易。更大的好處還有,其它一些公用程序,如lint,可以在使用分析邏輯的同時(shí)免受代碼生成邏輯之累。不幸的是,向集合中增加新的對(duì)象往往需要修改已經(jīng)寫(xiě)好的Visitor類(lèi)。本文提出了一種在Java中實(shí)現(xiàn)Visitor模式的更靈活的方法:使用Reflection(反射)。

-------------------------------------------------------------

集合(Collection)普遍應(yīng)用于面向?qū)ο缶幊讨校步?jīng)常引發(fā)一些和代碼有關(guān)的疑問(wèn)。例如,"如果一個(gè)集合存在不同的對(duì)象,該如何對(duì)它執(zhí)行操作?"

一種方法是,對(duì)集合中的每個(gè)元素進(jìn)行迭代,然后基于所在的類(lèi),對(duì)每個(gè)元素分別執(zhí)行對(duì)應(yīng)的操作。這會(huì)很難辦,特別是,如果你不知道集合中有什么類(lèi)型的對(duì)象。例如,假設(shè)想打印集合中的元素,你可以寫(xiě)出如下的一個(gè)方法(method):

public void messyPrintCollection(Collection collection) {
 Iterator iterator = collection.iterator()
 while (iterator.hasNext())
System.out.println(iterator.next().toString())
}

這看起來(lái)夠簡(jiǎn)單的了。它只不過(guò)調(diào)用了Object.toString()方法,然后打印出對(duì)象,對(duì)嗎?但如果有一組哈希表怎么辦?事情就會(huì)開(kāi)始變得復(fù)雜起來(lái)。你必須檢查從集合中返回的對(duì)象的類(lèi)型:

public void messyPrintCollection(Collection collection) {
 Iterator iterator = collection.iterator()
 while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Collection)
 messyPrintCollection((Collection)o);
else
 System.out.println(o.toString());
 }
}

不錯(cuò),現(xiàn)在已經(jīng)解決了嵌套集合的問(wèn)題,但它需要對(duì)象返回String,如果有其它不返回String的對(duì)象存在怎么辦?如果想在String對(duì)象前后添加引號(hào)以及在Float后添加f又該怎么辦?代碼還是越來(lái)越復(fù)雜:

public void messyPrintCollection(Collection collection) {
 Iterator iterator = collection.iterator()
 while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Collection)
 messyPrintCollection((Collection)o);
else if (o instanceof String)
 System.out.println("'"+o.toString()+"'");
else if (o instanceof Float)
 System.out.println(o.toString()+"f");
else
 System.out.println(o.toString());
 }
}

可以看到,事情的復(fù)雜度會(huì)急劇增長(zhǎng)。你當(dāng)然不想讓一段代碼到處充斥著if-else語(yǔ)句!那怎么避免呢?Visitor模式可以幫你。

要實(shí)現(xiàn)Visitor模式,得為訪問(wèn)者建立一個(gè)Visitor接口,還要為被訪問(wèn)的集合建立一個(gè)Visitable接口。然后,讓具體類(lèi)實(shí)現(xiàn)Visitor和Visitable接口。這兩個(gè)接口如下所示:

public interface Visitor
{
 public void visitCollection(Collection collection);
 public void visitString(String string);
 public void visitFloat(Float float);
}

public interface Visitable
{
 public void accept(Visitor visitor);
}

對(duì)于具體的String,可能是這樣:

public class VisitableString implements Visitable
{
 private String value;
 public VisitableString(String string) {
value = string;
 }
 public void accept(Visitor visitor) {
visitor.visitString(this);
 }
}

在accept方法中,對(duì)this類(lèi)型調(diào)用正確的visitor方法:

visitor.visitString(this)

這樣,就可以如下實(shí)現(xiàn)具體的Visitor:

public class PrintVisitor implements Visitor
{
 public void visitCollection(Collection collection) {
Iterator iterator = collection.iterator()
while (iterator.hasNext()) {
Object o = iterator.next();
if (o instanceof Visitable)
 ((Visitable)o).accept(this);
 }

 public void visitString(String string) {
System.out.println("'"+string+"'");
 }

 public void visitFloat(Float float) {
System.out.println(float.toString()+"f");
 }
}

實(shí)現(xiàn)VisitableFloat和VisitableCollection類(lèi)的時(shí)候,它們也是各自調(diào)用合適的Visitor方法,所得到的效果和前面那個(gè)用了if-else的messyPrintCollection方法一樣,但這里的手法更干凈。在visitCollection()中,調(diào)用的是Visitable.accept(this),然后這個(gè)調(diào)用又返回去調(diào)用一個(gè)合適的Visitor方法。這被稱(chēng)做 "雙分派";即,Visitor先調(diào)用了Visitable類(lèi)中的方法,這個(gè)方法又回調(diào)到Visitor類(lèi)中。

雖然通過(guò)實(shí)現(xiàn)visitor消除了if-else語(yǔ)句,卻也增加了很多額外的代碼。最初的String和Float對(duì)象都要用實(shí)現(xiàn)了Visitable接口的對(duì)象進(jìn)行包裝。這有點(diǎn)討厭,但一般說(shuō)來(lái)不是問(wèn)題,因?yàn)槟憧梢宰尳?jīng)常被訪問(wèn)的集合只包含那些實(shí)現(xiàn)了Visitable接口的對(duì)象。

但似乎這還是額外的工作。更糟糕的是,當(dāng)增加一個(gè)新的Visitable類(lèi)型如VisitableInteger時(shí),會(huì)發(fā)生什么呢?這是Visitor模式的一個(gè)重大缺陷。如果想增加一個(gè)新的Visitable對(duì)象,就必須修改Visitor接口,然后對(duì)每一個(gè)Visitor實(shí)現(xiàn)類(lèi)中的相應(yīng)的方法一一實(shí)現(xiàn)。你可以用一個(gè)帶缺省空操作的Visitor抽象基類(lèi)來(lái)代替接口。那就很象Java GUI中的Adapter類(lèi)。那個(gè)方法的問(wèn)題在于,它需要占用單繼承;而你往往想保留單繼承,讓它用于其它什么東西,比如繼承StringWriter。那個(gè)方法還有限制,它只能夠成功訪問(wèn)Visitable對(duì)象。

幸運(yùn)的是,Java可以讓Visitor模式更靈活,使得你可以隨心所欲地增加Visitable對(duì)象。怎么做?答案是,使用Reflection。比如,可以設(shè)計(jì)這樣一個(gè)ReflectiveVisitor接口,它只需要一個(gè)方法:

public interface ReflectiveVisitor {
 public void visit(Object o);
}

就這樣,很簡(jiǎn)單。至于Visitable,還是和前面一樣,我過(guò)一會(huì)兒再說(shuō)。現(xiàn)在先用Reflection來(lái)實(shí)現(xiàn)PrintVisitor:

public class PrintVisitor implements ReflectiveVisitor {
 public void visitCollection(Collection collection)
 { ... same as above ... }
 public void visitString(String string)
 { ... same as above ... }
 public void visitFloat(Float float)
 { ... same as above ... }

 public void default(Object o)
 {
System.out.println(o.toString());
 }

 public void visit(Object o) {
// Class.getName() returns package information as well.
// This strips off the package information giving us
// just the class name
String methodName = o.getClass().getName();
methodName = "visit"+
 methodName.substring(methodName.lastIndexOf('.')+1);
// Now we try to invoke the method visit
try {
 // Get the method visitFoo(Foo foo)
 Method m = getClass().getMethod(methodName,
new Class[] { o.getClass() });
 // Try to invoke visitFoo(Foo foo)
 m.invoke(this, new Object[] { o });
} catch (NoSuchMethodException e) {
 // No method, so do the default implementation
 default(o);
}
 }
}

現(xiàn)在不需要Visitable包裝類(lèi)。僅僅只是調(diào)用visit(),請(qǐng)求就會(huì)分發(fā)到正確的方法上。很不錯(cuò)的一點(diǎn)是,只要認(rèn)為適合,visit()就可以分發(fā)。這并非必須使用reflection--它可以使用其它完全不同的機(jī)制。

新的PrintVisitor中,有針對(duì)Collection,String和Float而寫(xiě)的方法,但然后它又在catch語(yǔ)句中捕捉所有未處理的類(lèi)型。你要擴(kuò)展visit()方法,使得它也能夠處理所有的父類(lèi)。首先,得增加一個(gè)新方法,稱(chēng)為getMethod(Class c),它返回的是要調(diào)用的方法;為了找到這個(gè)相匹配的方法,先在類(lèi)c的所有父類(lèi)中尋找,然后在類(lèi)c的所有接口中尋找。

protected Method getMethod(Class c) {
 Class newc = c;
 Method m = null;
 // Try the superclasses
 while (m == null && newc != Object.class) {
String method = newc.getName();
method = "visit" + method.substring(method.lastIndexOf('.') + 1);
try {
 m = getClass().getMethod(method, new Class[] {newc});
} catch (NoSuchMethodException e) {
 newc = newc.getSuperclass();
}
 }
 // Try the interfaces.If necessary, you
 // can sort them first to define 'visitable' interface wins
 // in case an object implements more than one.
 if (newc == Object.class) {
Class[] interfaces = c.getInterfaces();
for (int i = 0; i < interfaces.length; i++) {
 String method = interfaces[i].getName();
 method = "visit" + method.substring(method.lastIndexOf('.') + 1);
 try {
m = getClass().getMethod(method, new Class[] {interfaces[i]});
 } catch (NoSuchMethodException e) {}
}
 }
 if (m == null) {
try {
 m = thisclass.getMethod("visitObject", new Class[] {Object.class});
} catch (Exception e) {
// Can't happen
}
 }
 return m;
}

看起來(lái)有些復(fù)雜,其實(shí)不然。實(shí)際上,它只是根據(jù)傳進(jìn)來(lái)的類(lèi)名去尋找相應(yīng)的方法而已。如果沒(méi)找到,就在父類(lèi)中找;還沒(méi)找到,再到接口中找。最后,就拿visitObject()作為缺省。

注意,為了照顧那些熟悉傳統(tǒng)Visitor模式的讀者,我對(duì)方法的名稱(chēng)采用了傳統(tǒng)的命名方式。但正如你們一些人所注意到的,把所有的方法命名為 "visit" 然后讓參數(shù)類(lèi)型作為區(qū)分會(huì)更高效。但這樣做的話,你得把主visit(Object o)方法的名字改為dispatch(Object o)之類(lèi)。否則,就沒(méi)有一個(gè)缺省方法可用了,你就得在調(diào)用visit(Object o)時(shí)將類(lèi)型轉(zhuǎn)換為Object,以保證visit采用的是正確的調(diào)用方式。

現(xiàn)在可以修改visit()方法,以利用getMethod():

public void visit(Object object) {
 try {
 Method method = getMethod(getClass(), object.getClass());
 method.invoke(this, new Object[] {object});
 } catch (Exception e) { }
}

現(xiàn)在,visitor對(duì)象的功能強(qiáng)大多了。你可以傳進(jìn)任何對(duì)象,并且有某個(gè)方法處理它。另外一個(gè)好處是,還有一個(gè)缺省方法visitObject(Object o),它可以捕捉任何未知的對(duì)象。再多花點(diǎn)工夫,你還可以寫(xiě)出一個(gè)visitNull()方法。

我在上面對(duì)Visitable接口避而不談自有原因。傳統(tǒng)Visitor模式的另一個(gè)好處是,它允許Visitable對(duì)象來(lái)控制對(duì)對(duì)象結(jié)構(gòu)的訪問(wèn)。例如,假設(shè)有一個(gè)實(shí)現(xiàn)了Visitable的TreeNode對(duì)象,你可以讓一個(gè)accept()方法來(lái)遍歷它的左右節(jié)點(diǎn):

public void accept(Visitor visitor) {
 visitor.visitTreeNode(this);
 visitor.visitTreeNode(leftsubtree);
 visitor.visitTreeNode(rightsubtree);
}

這樣,只用對(duì)Visitor類(lèi)再進(jìn)行一點(diǎn)修改,就可以進(jìn)行Visitable控制訪問(wèn):

public void visit(Object object) throws Exception
{
Method method = getMethod(getClass(), object.getClass());
 method.invoke(this, new Object[] {object});
 if (object instanceof Visitable)
 {
callAccept((Visitable) object);
 }
}
public void callAccept(Visitable visitable) {
 visitable.accept(this);
}

如果已經(jīng)實(shí)現(xiàn)了一個(gè)Visitable對(duì)象結(jié)構(gòu),可以保留callAccept()方法并使用Visitable控制訪問(wèn)。如果想在visitor中訪問(wèn)結(jié)構(gòu),只需改寫(xiě)callAccept()方法,使之什么也不做。

想讓數(shù)個(gè)不同的訪問(wèn)者對(duì)同一個(gè)對(duì)象集合進(jìn)行訪問(wèn)時(shí),Visitor模式可以發(fā)揮它的強(qiáng)大作用。假設(shè)已經(jīng)有一個(gè)解釋器,一個(gè)中綴寫(xiě)作器,一個(gè)后綴寫(xiě)作器,一個(gè)XML寫(xiě)作器和一個(gè)SQL寫(xiě)作器,它們都作用在同一個(gè)對(duì)象集合上。那么,也可以很容易地為相同的對(duì)象集合寫(xiě)出一個(gè)前綴寫(xiě)作器和一個(gè)SOAP寫(xiě)作器。另外,這些寫(xiě)作器可以正常地和它們所不知道的對(duì)象工作;當(dāng)然,如果愿意,也可以讓它們拋出異常。

結(jié)論
通過(guò)使用Java Reflection,你可以增強(qiáng)Visitor模式,使之具有操作對(duì)象結(jié)構(gòu)的強(qiáng)大功能,并在增加新Visitable類(lèi)型方面提供靈活性。希望你在以后的程序設(shè)計(jì)中能夠應(yīng)用這一模式。

溫馨提示:喜歡本站的話,請(qǐng)收藏一下本站!

本類(lèi)教程下載

系統(tǒng)下載排行

国产午夜成人免费看片无遮挡_日本免费xxxx色视频_免费人成网上在线观看_黄网址在线永久免费观看

  • <label id="pxtpz"><meter id="pxtpz"></meter></label>
      1. <span id="pxtpz"><optgroup id="pxtpz"></optgroup></span>

        中文字幕成人在线观看| 欧美日韩国产高清一区二区三区 | 亚洲国产成人va在线观看天堂| 国产69精品一区二区亚洲孕妇| 久久只精品国产| 高潮精品一区videoshd| 国产精品美女久久久久久2018| 不卡视频一二三| 亚洲综合丝袜美腿| 日韩欧美高清在线| 成人开心网精品视频| 艳妇臀荡乳欲伦亚洲一区| 制服丝袜亚洲网站| 成人动漫一区二区| 五月天精品一区二区三区| 亚洲精品在线免费观看视频| av激情综合网| 久久97超碰国产精品超碰| 国产精品天美传媒| 91精品国产综合久久国产大片| 国产成人亚洲精品青草天美| 一区二区三区加勒比av| 久久久不卡影院| 欧美三级电影在线看| 国内一区二区视频| 亚洲韩国一区二区三区| 日本一区二区三级电影在线观看 | 色综合一区二区| 天天色天天爱天天射综合| 久久综合九色欧美综合狠狠| 91丨porny丨最新| 麻豆一区二区在线| 亚洲综合丁香婷婷六月香| 国产亚洲精品福利| 777奇米成人网| 91麻豆123| 国产91在线看| 国产一区欧美二区| 久久99热这里只有精品| 一区二区三区在线视频观看58| 精品久久久久一区| 欧美日韩日日夜夜| 一本久久综合亚洲鲁鲁五月天| 激情综合色播激情啊| 亚洲成av人片在www色猫咪| 国产精品麻豆久久久| 欧美不卡一二三| 制服视频三区第一页精品| 色系网站成人免费| 99热精品国产| eeuss鲁片一区二区三区| 国产盗摄视频一区二区三区| 久久精品国产99国产精品| 天天综合网 天天综合色| 亚洲美女精品一区| 亚洲日本韩国一区| 亚洲精品中文在线影院| 日韩伦理免费电影| 亚洲欧美欧美一区二区三区| 国产精品久久久久国产精品日日| 欧美mv日韩mv亚洲| 26uuu亚洲综合色| 国产色91在线| 中文字幕在线观看一区二区| 久久久影视传媒| 精品成人免费观看| 久久综合久久鬼色中文字| 日韩欧美一区二区视频| 91精品国产丝袜白色高跟鞋| 欧美高清视频不卡网| 欧美日韩免费在线视频| 欧美在线高清视频| 91精品国产综合久久精品性色| 欧美性猛交xxxxxxxx| 欧美最猛黑人xxxxx猛交| 欧洲视频一区二区| 在线观看区一区二| 7777精品伊人久久久大香线蕉| 91精品国产综合久久小美女| 欧美一区二区高清| 制服丝袜成人动漫| 6080国产精品一区二区| 精品国产成人系列| 久久蜜桃一区二区| 亚洲国产精品t66y| 亚洲自拍欧美精品| 乱一区二区av| 国产精品一线二线三线精华| 成人性生交大片免费看在线播放 | 国产一二精品视频| 国产精品一二三区| 91在线你懂得| 欧美精品色一区二区三区| 精品久久国产老人久久综合| 中文字幕av一区二区三区高 | 日韩视频123| 久久久青草青青国产亚洲免观| |精品福利一区二区三区| 亚洲成人自拍一区| 日韩精品国产欧美| 韩国三级在线一区| 在线观看精品一区| 欧美精品日韩一区| 成人欧美一区二区三区黑人麻豆| 亚洲精品菠萝久久久久久久| 日本中文字幕一区二区有限公司| 国产综合色在线| 欧美日韩在线播放三区| 国产日产精品一区| 午夜精品久久久久影视| 国产风韵犹存在线视精品| 在线这里只有精品| 2020国产精品| 日日骚欧美日韩| 成人午夜激情在线| 欧美一区二区三区思思人| 成人免费在线视频| 国产在线视频精品一区| 欧美性xxxxxxxx| 精品99999| 午夜精彩视频在线观看不卡| 成人avav在线| 日韩一区二区免费在线电影| 亚洲一二三四在线| 9i看片成人免费高清| 精品美女在线播放| 亚洲欧美日韩久久精品| 国产99精品在线观看| 日韩色视频在线观看| 亚洲国产成人av好男人在线观看| 国产99久久久国产精品潘金网站| 日韩一区二区免费在线电影| 亚洲永久免费视频| 91在线视频播放地址| 亚洲欧美中日韩| 豆国产96在线|亚洲| 久久久亚洲欧洲日产国码αv| 亚洲福利一区二区| 在线观看亚洲精品| 亚洲一区成人在线| 欧美日韩另类一区| 一区二区三区高清不卡| 一本大道av一区二区在线播放| 中文字幕欧美激情一区| 国产成人自拍网| 国产精品视频免费看| 成人免费毛片嘿嘿连载视频| 国产精品色在线观看| 国产aⅴ综合色| 日本一区二区三区国色天香| 成人中文字幕合集| 成人免费在线观看入口| av一区二区不卡| 国产精品久久久久精k8 | 日韩一区二区三区在线视频| 一级中文字幕一区二区| 99免费精品视频| 亚洲六月丁香色婷婷综合久久 | 成人免费看片app下载| 国产精品亲子伦对白| 91视频www| 午夜精品久久久久久| 久久综合狠狠综合久久激情| 成人av先锋影音| 亚洲成人动漫精品| 日韩精品在线网站| 岛国一区二区三区| 午夜精品久久久久久不卡8050| 欧美va天堂va视频va在线| 日本不卡的三区四区五区| 欧美成人艳星乳罩| 成人av中文字幕| 午夜久久电影网| 国产精品久久久久影视| 7777精品久久久大香线蕉| 高清国产一区二区| 免费在线观看一区二区三区| 久久精品水蜜桃av综合天堂| 欧美最新大片在线看| 国产乱国产乱300精品| 亚洲一卡二卡三卡四卡五卡| 久久久91精品国产一区二区精品 | 日韩欧美国产综合在线一区二区三区 | 26uuu色噜噜精品一区| 成人av中文字幕| 久久99久久精品| 亚洲图片欧美综合| 亚洲男女一区二区三区| 国产欧美一区二区在线观看| 欧美一区二区女人| 欧美视频精品在线| caoporn国产一区二区| 国产一区二区主播在线| 亚洲成av人在线观看| 亚洲特级片在线| 国产精品每日更新| 欧美国产一区二区| 久久久久久黄色| 久久久午夜电影| 久久久久国色av免费看影院|