首頁 > Java > java教程 > 主體

Java實作在訪客模式中使用反射的範例程式碼分享

黄舟
發布: 2017-03-23 11:13:33
原創
1243 人瀏覽過

集合類型在面對物件程式中很常用,這也帶來一些程式碼相關的問題。 」

一種做法就是遍歷集合中的每個元素,然後根據它的類型而做具體的操作。這會很複雜,尤其當你不知道集合中元素的類型時。如果y要列印集合中的元素,可以寫一個這樣的方法:

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

看起來很簡單。包含hashtable的vector呢?字串

不是你想要的呢? ##
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());
        }
}
登入後複製

程式碼很快就變得雜亂了。 ##為實作訪客模式,你需要建立一個Visitor介面,為被存取的集合物件建立一個Visitable介面。大致如下:

對於一個具體的String類,可以這麼實作:

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);
}
登入後複製

在accept方法中,根據不同的類型,呼叫visitor中對應的方法:

#visitor.visitString(this)

具體Visitor的實作方式如下:

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

到時候,只要實作了VisitableFloat類別和VisitableCollection類別並呼叫適當的visitor方法,你就可以去掉包含一堆if-else結構的messyPrintCollection方法,採用十分清爽的方式實作了相同的功能。呼叫了visitor中正確的方法。語句不見了,但還是引入了很多附加的程式碼。你可以限制被存取集合只能包含Visitable物件。

然而,這還有很多附加的工作要做。更糟的是,當你想增加一個新的Visitable類型時怎麼辦,例如VisitableInteger?這是訪客模式的一個主要缺點。如果你想要增加一個新的Visitable類型,你必須改變Visitor介面以及每個實作Visitor介面方法的類別。你可以不把Visitor設計為接口,取而代之,可以把Visitor設計為一個有

空運算

的抽象基底類別。這與Java GUI中的Adapter類別很相似。這麼做的問題是你會用盡單次繼承,而常見的情形是你還想用繼承實作其他功能,像是繼承StringWriter類別。這同樣只能成功存取實作Visitable介面的物件。

幸運的是,Java可以讓你的訪客模式更靈活,你可以依照你的意願增加Visitable物件。怎麼實現呢?答案是使用反射。使用反射的ReflectiveVisitor介面只需要一個方法:

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");
    }
}
登入後複製

好了,上面很簡單。 Visitable介面先不動,我會說。現在,我使用反射實作PrintVisitor類別。

public interface ReflectiveVisitor {
    public void visit(Object o);
}
登入後複製

現在你不需要使用Visitable包裝類別(包裝了原始型別String、Float)。你可以直接存取visit(),它會呼叫正確的方法。 visit()的一個優點是它會分派它認為合適的方法。這不一定使用反射,可以使用完全不同的一種機制。

在新的PrintVisitor類別中,有對應於Collections、String和Float的操作方法;對於不能處理的類型,可以透過catch語句捕捉。對於不能處理的類型,可以透過擴充visit()方法來嘗試處理它們的所有超類別。首先,增加一個新的方法getMethod(Class c),回傳值就是一個可被觸發的方法。它會搜尋Class c的所有父類別和接口,以找到一個匹配方法。

这看上去很复杂,实际上并不。大致来说,首先根据传入的class名称搜索可用方法;如果没找到,就尝试从父类搜索;如果还没找到,就从接口中尝试。最后,(仍没找到)可以使用visitObject()作为默认方法。

由于大家对传统的访问者模式比较熟悉,这里沿用了之前方法命名的惯例。但是,有些人可能注意到,把所有的方法都命名为“visit”并通过参数类型不同来区分,这样更高效。然而,如果你这么做,你必须把visit(Object o)方法的名称改为其他,比如dispatch(Object o)。否则,(当没有对应处理方法时),你无法退回到默认的处理方法,并且当你调用visit(Object o)方法时,为了确保正确的方法调用,你必须将参数强制转化为Object。

为了利用getMethod()方法,现在需要修改一下visit()方法。

现在,visitor类更加强大了——可以传入任意的对象并且有对应的处理方法。另外,有一个默认处理方法,visitObject(Object o),的好处就是就可以捕捉到任何没有明确说明的类型。再稍微修改下,你甚至可以添加一个visitNull()方法。

我仍保留Visitable接口是有原因的。传统访问者模式的另一个好处是它可以通过Visitable对象控制对象结构的遍历顺序。举例来说,假如有一个实现了Visitable接口的类TreeNode,它在accept()方法中遍历自己的左右节点。

这样,只要修改下Visitor类,就可以通过Visitable类控制遍历:

如果你实现了Visitable对象的结构,你可以保持callAccept()不变,就可以使用Visitable控制的对象遍历。如果你想在visitor中遍历对象结构,你只需重写allAccept()方法,让它什么都不做。

当使用几个不同的visitor去操作同一个对象集合时,访问者模式的力量就会展现出来。比如,当前有一个解释器、中序遍历器、后续遍历器、XML编写器以及SQL编写器,它们可以处理同一个对象集合。我可以轻松地为这个集合再写一个先序遍历器或者一个SOAP编写器。另外,它们可以很好地兼容它们不识别的类型,或者我愿意的话可以让它们抛出异常。

总结

使用Java反射,可以使访问者模式提供一种更加强大的方式操作对象结构,可以按照需求灵活地增加新的Visitable类型。我希望在你的编程之旅中可以使用访问者模式。

以上是Java實作在訪客模式中使用反射的範例程式碼分享的詳細內容。更多資訊請關注PHP中文網其他相關文章!

來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!