2013-12-09 69 views
3

這裏的遊客設計模式的背景下/示例代碼。方法命名

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

public class Book implements Visitable{ 
    public void accept(Visitor v){ 
     v.visit(this); 
    } 
    public void read() {} 
    /** 
    book stuff 
    **/ 
} 
public class Movie implements Visitable{ 
    public void accept(Visitor v){ 
     v.visit(this); 
    } 
    public void watch() {} 
    /** 
    movie stuff 
    **/ 
} 

public interface Visitor{ 
    public void visit(Book b); 
    public void visit(Movie m); 
} 

public class Person implements Visitor{ 
    public void visit(Book b){ 
     b.read(); 
    } 
    public void visit(Movie m){ 
     m.watch(); 
    } 
} 

我的教練說,這是沒有一個好主意,超載visit方法,我應該給一個獨特的名字,看起來像下面的每次訪問方法。我不相信這個想法。有人可以解釋什麼是超載visit方法的缺點?

public interface Visitor{ 
    public void visitBook(Book b); 
    public void visitMovie(Movie m); 
} 

public class Person implements Visitor{ 
    public void visitBook(Book b){ 
     b.read(); 
    } 
    public void visitMovie(Movie m){ 
     m.watch(); 
    } 
} 
+1

我也想知道這個答案,因爲我同意你的看法。我從來沒有見過這樣做的實現。除了笨拙地閱讀,我覺得有方法名稱反映你正在訪問的抽象是很奇怪的。這些參數包含在內。 – Vidya

+0

@Vidya然後投票贊成:D – xiamx

+0

完成。讓我們看看發生了什麼。 – Vidya

回答

3

約翰·弗利賽德斯的書模式孵化(GOF的作家之一,他的書有時被認爲是一種補充設計模式)解釋這兩者的優勢,以實現訪客兩種方式。

他說,使用不同的變量名的原因是這樣的:

了較大幅度的優勢是當有一個resonalbe默認行爲,和子類往往忽略短短的操作。當我們超載時,子類必須覆蓋的所有的功能;否則你友好的C++編譯器可能會抱怨你的選擇性覆蓋隱藏了一個或多個基類操作。當我們爲訪客操作提供不同的名稱時,我們會解決這個問題。然後子類可以不受懲罰地重新定義一部分操作。 - 圖案孵化p.36

+0

謝謝,這聽起來像一個很好的論點。這是C++編譯器獨有的「特性」還是OO語言(C#,java)中的一般行爲? – xiamx

+0

我相信這是C++的特定行爲。對於Java,根據JLS§9.4.1:在逐個簽名的基礎上覆蓋方法。 '例如,如果一個接口聲明兩個具有相同名稱的公共方法(第9.4.2節),並且子接口覆蓋其中一個,則該子接口仍然繼承另一個方法。 ' – dkatzel

0

四人幫,也就是模式聖經,按照你的教官的建議。

訪問類定義應該像在C++:

class Visitor { 
public: 
    virtual void VisitElementA(ElementA*); 
    virtual void VisitElementB(ElementB*); 

    // and so on for other concrete elements 
protected: 
    Visitor(); 
}; 

結案。

查看我在@ vadya的回答上述觀點:超載暗示方法做同樣的事情,但支持的東西在不同的類型,這是不符合觀衆的情況。

+0

這背後的理由是什麼?我可以在教科書中找到使用重載的例子,但這並不能回答我的問題。 – xiamx

+0

我想說如果你認爲「四人幫」是錯的,你需要提供理由。我通常儘量避免在類型是param的方法中提及類型,但我認爲在這種情況下它確實有意義,因爲訪問者的整個想法就是所有在任何地方都能做的事情的方法。 – Rob

+0

我喜歡Go4和設計模式的想法,就像下一個人一樣,但是盲目而虔誠地接受某些東西毫無疑問是任何事情中的一個糟糕主意。此外,OP並沒有說Go4是「錯誤的」。他在問爲什麼他的想法也無法工作。這比黑白的正確或錯誤問題更細緻。我們不要忘記來自歐比旺的偉大[課程](http://www.youtube.com/watch?v=wgpytjlW5wU)。 – Vidya

0

按我的理解Visitor設計模式的目的是解決單一問題調度的問題。 訪問者模式提供雙重分派方法。動態分派僅基於調用對象的類型,只有使用覆蓋而不是超載才能實現。 使用重載將讓函數依賴於調用期間傳遞的參數,我們不想在訪問者中使用它。

使用重載超載以上的整個概念是實現訪客雙調度機制。

+1

「動態調度只基於調用對象的類型,只能使用覆蓋而不是重載」<不正確 – xiamx

+0

按照我的理解動態調度機制是我們所說的運行時多態性,它在運行時被解析,而重載是一個編譯如果你能給我提供一些例子來證明錯誤的說法,這對我來說是一個很大的幫助,並且可以改進這個概念,但是這對於動態調度是不可能的。 –