中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

什么是訪問者模式

發布時間:2021-10-19 09:16:03 來源:億速云 閱讀:173 作者:iii 欄目:web開發

這篇文章主要介紹“什么是訪問者模式”,在日常操作中,相信很多人在什么是訪問者模式問題上存在疑惑,小編查閱了各式資料,整理出簡單好用的操作方法,希望對大家解答”什么是訪問者模式”的疑惑有所幫助!接下來,請跟著小編一起來學習吧!

訪問者模式,重點在于訪問者二字。說到訪問,我們腦海中必定會想起新聞訪談,兩個人面對面坐在一起。從字面上的意思理解:其實就相當于被訪問者(某個公眾人物)把訪問者(記者)當成了外人,不想你隨便動。你想要什么,我弄好之后給你(調用你的方法)。

01 什么是訪問者模式?

訪問者模式的定義如下所示,說的是在不改變數據結構的提前下,定義新操作。

封裝一些作用于某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義作用于這些元素的新的操作。

但在實際的應用中,我發現有些例子并不是如此。有些例子中并沒有穩定的數據結構,而是穩定的算法。在樹義看來,訪問者模式是:把不變的固定起來,變化的開放出去。

我們舉生活中一個例子來聊聊:某科學家接受記者訪談。我們都知道科學家接受訪問,肯定是有流程上的限制的,不可能讓你隨便問。我們假設這個過程是:先問科學家的學校經歷,再聊你的工作經歷,最后聊你的科研成果。那么在這個過程中,固定的是什么東西呢?固定的是接受采訪的流程。變化的是什么呢?變化的是不同的記者,針對學校經歷,可能會提不同的問題。

根據我們之前的理解,訪問者模式其實就是要把不變的東西固定起來,變化的開放出去。那么對于科學家接受訪談這個事情,我們可以這么將其抽象化。

首先,我們需要有一個 Visitor 類,這里定義了一些外部(記者)可以做的事情(提學校經歷、工作經歷、科研成就的問題)。

public interface Visitor {     public void askSchoolExperience(String name);     public void askWorkExperience(String name);     public void askScienceAchievement(String name); }

接著聲明一個 XinhuaVisitor 類去實現 Visitor 類,這表示是新華社的一個記者(訪問者)想去訪問科學家。

public class XinhuaVisitor implements Visitor{     @Override     public void askSchoolExperience(String name) {         System.out.printf("請問%s:在學校取得的最大成就是什么?\n", name);     }      @Override     public void askWorkExperience(String name) {         System.out.printf("請問%s:工作上最難忘的事情是什么?\n", name);     }      @Override     public void askScienceAchievement(String name) {         System.out.printf("請問%s:最大的科研成果是什么?", name);     } }

接著聲明一個 Scientist 類,表明是一個科學家。科學家通過一個 accept ()  方法接收記者(訪問者)的訪問申請,將其存儲起來。科學家定義了一個 interview  方法,將訪問的流程固定死了,只有教你問什么的時候,我才會讓你(記者)提問。

public class Scientist {      private Visitor visitor;      private String name;      private Scientist(){}      public Scientist(String name) {         this.name = name;     }      public void accept(Visitor visitor) {         this.visitor = visitor;     }      public void interview(){         System.out.println("------------訪問開始------------");         System.out.println("---開始聊學校經歷---");         visitor.askSchoolExperience(name);         System.out.println("---開始聊工作經歷---");         visitor.askWorkExperience(name);         System.out.println("---開始聊科研成果---");         visitor.askScienceAchievement(name);     } }

最后我們聲明一個場景類 Client,來模擬訪談這一過程。

public class Client {     public static void main(String[] args) {         Scientist yang = new Scientist("楊振寧");         yang.accept(new XinhuaVisitor());         yang.interview();     } }

運行的結果為:

------------訪問開始------------ ---開始聊學校經歷--- 請問楊振寧:在學校取得的最大成就是什么? ---開始聊工作經歷--- 請問楊振寧:工作上最難忘的意見事情是什么? ---開始聊科研成果--- 請問楊振寧:最大的科研成果是什么?

看到這里,大家對于訪問者模式的本質有了更感性的認識(把不變的固定起來,變化的開放出去)。在這個例子中,不變的固定的就是訪談流程,變化的就是你可以提不同的問題。

一般來說,訪問者模式的類結構如下圖所示:

什么是訪問者模式

  • Visitor  訪問者接口。訪問者接口定義了訪問者可以做的事情。這個需要你去分析哪些是可變的,將這些可變的內容抽象成訪問者接口的方法,開放出去。而被訪問者的信息,其實就是通過訪問者的參數傳遞過去。

  • ConcreteVisitor  具體訪問者。具體訪問者定義了具體某一類訪問者的實現。對于新華社記者來說,他們更關心楊振寧科學成果方面的事情,于是他們提問的時候更傾向于挖掘成果。但對于青年報記者來說,他們的讀者是青少年,他們更關心楊振寧在學習、工作中的那種精神。

  • Element 具體元素。這里指的是具體被訪問的類,在我們這個例子中指的是 Scientist 類。一般情況下,我們會提供一個 accept ()  方法,接收訪問者參數,將相當于接受其范文申請。但這個方法也不是必須的,只要你能夠拿到 visitor 對象,你怎么定義這個參數傳遞都可以。

對于訪問者模式來說,最重要的莫過于 Visitor、ConcreteVisitor、Element  這三個類了。Visitor、ConcreteVisitor 定義訪問者具體能做的事情,被訪問者的參數通過參數傳遞給訪問者。Element  則通過各種方法拿到被訪問者對象,常用的是通過 accept () 方法,但這并不是絕對的。

需要注意的是,我們學習設計模式重點是理解類與類之間的關系,以及他們傳遞的信息。至于是通過什么方式傳遞的,是通過 accept ()  方法,還是通過構造函數,都不是重點。

02 訪問者模式的實際應用

前面我們用一個生活的例子幫助大家理解訪問者模式,相信大家對訪問者模式應該有了個感性的理解了。為了回歸編程實踐本身,讓大家對訪問者模式能有更好的實踐理解。下面我們將從軟件編程上講講訪問者模式在開源框架中的應用。

文件樹遍歷

JDK  中有文件操作,我們自然是清楚的。有文件操作,那自然就會有文件夾的遍歷操作,即訪問某個文件夾下面的所有文件或文件夾。試想一下,如果我們想要打印出某個文件夾下所有文件及文件夾的名字,我們需要怎么做?

很簡單的做法,其實就是直接做一個樹的遍歷,然后將名字打印出來呀!

沒錯,這確實是正確答案!

那么如果我希望統計一下所有文件及文件夾的個數呢?

那就再遍歷一次,然后用一個計數器去一直加一唄!

沒錯,這也是正確答案!

但你是否發現了這兩個過程中,我們有一個相同的操作:遍歷文件樹。無論是打印文件名,還是計算文件樹,我們都需要去遍歷文件樹。而無論哪一個過程,我們最終要的其實就是訪問文件。

還記得我們說過設計模式的本質是什么嗎?設計模式的本質是找出不變的東西,再找出變化的東西,然后找到合適的數據結構(設計模式)去承載這種變化。

在這個例子里,不變的東西是文件樹的遍歷,變化的是對于文件的不同訪問操作。很顯然,訪問者模式是比較適合承載這種變化的。我們可以把這種不變的東西(文件樹的遍歷)固定起來,把變化的東西(文件的具體操作)開放出去。JDK  對于文件樹的遍歷,其實就是使用訪問者模式實現的。

JDK 中聲明了一個 FileVisitor 接口,定義了遍歷者可以做的操作。

public interface FileVisitor<T> {     FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs);     FileVisitResult visitFile(T file, BasicFileAttributes attrs)         throws IOException;     FileVisitResult visitFileFailed(T file, IOException exc)         throws IOException;     FileVisitResult postVisitDirectory(T dir, IOException exc)         throws IOException; }

FileVisitor 中定義的 visitFile () 方法,其實就是對于文件的訪問。被訪問者(文件)的信息通過第一個參數 file  傳遞過來。這樣遍歷者就可以訪問文件的內容了。

SimpleFileVisitor 則是對于 FileVisitor 接口的實現,該類中僅僅是做了簡單的參數校驗,并沒有太過的邏輯。

public class SimpleFileVisitor<T> implements FileVisitor<T> {     @Override     public FileVisitResult preVisitDirectory(T dir, BasicFileAttributes attrs)         throws IOException     {         Objects.requireNonNull(dir);         Objects.requireNonNull(attrs);         return FileVisitResult.CONTINUE;     }          @Override     public FileVisitResult visitFile(T file, BasicFileAttributes attrs)         throws IOException     {         Objects.requireNonNull(file);         Objects.requireNonNull(attrs);         return FileVisitResult.CONTINUE;     }     //....其他省略 }

FileVisitor 類和 SimpleFileVisitor 類對應的就是 UML 類圖中的 Visitor 和 ConcreteVisitor  類。而 Element 元素,對應的其實是 JDK 中的 Files 類。

什么是訪問者模式

Files 文件中遍歷文件樹是通過 walkFileTree () 方法實現的。在 walkFileTree ()  方法中實現了樹的遍歷,在遍歷到文件的時候會通過 visitor 類的 visitFile  方法調用遍歷者的方法,將遍歷到的文件傳遞給遍歷者,從而達到分離變化的目的。

ASM 修改字節碼

ASM 是 Java 的字節碼增強技術,這里面就用到了訪問者模式,主要是用來進行字節碼的修改。在 ASM  中與此相關的三個類分別是:ClassReader、ClassVisitor、ClassWriter。

ClassReader 類相當于訪問者模式中的 Element 元素。它將字節數組或 class 文件讀入內存中,并以樹的數據結構表示。該類定義了一個  accept 方法用來和 visitor 交互。

什么是訪問者模式

ClassVisitor 相當于抽象訪問者接口。ClassReader 對象創建之后,需要調用 accept () 方法,傳入一個  ClassVisitor 對象。在 ClassReader 的不同時期會調用 ClassVisitor 對象中不同的 visit ()  方法,從而實現對字節碼的修改。

什么是訪問者模式

ClassWriter 是 ClassVisitor 的是實現類,它負責將修改后的字節碼輸出為字節數組。

什么是訪問者模式

對于 ASM 這種場景而言,字節碼規范是非常嚴格且穩定的,如果隨便更改可能出問題。但我們又需要對字節碼進行動態修改,從而達到某些目的。在這種情況下,ASM  的設計者采用了訪問者模式將變化的部分隔離開來,將不變的部分固定下來,從而達到了靈活擴展的目的。

03 我們該如何使用?

從上面幾個例子,我們大致可以明白訪問者模式的使用場景:某些較為穩定的東西(數據結構或算法),不想直接被改變但又想擴展功能,這時候適合用訪問者模式。

說到對于訪問者模式使用場景的定義,我們會覺得模板方法模式與這個使用場景的定義很像。但它們還是有些許差別的。訪問者模式的變化與非變化(即訪問者與被訪問者)之間,它們只是簡單的包含關系,而模板方法模式的變化與非變化則是繼承關系。  但它們也確實有類似的地方,即都是封裝了固定不變的東西,開放了變動的東西。

訪問者模式的優點很明顯,即隔離了變化的東西,固定了不變的東西,使得整體的可維護性更強、具有更強的擴展性。但它也帶來了設計模式通用的一些缺點,例如:

  • 類結構變得復雜。之前我們可是簡單的調用關系,現在則是多個類之間的繼承和組合關系。從一定程度上,提高了對開發人員的要求,提高了研發成本。

  • 被訪問者的變更變得更加困難。例如我們上面科學家訪談的例子,如果科學家訪談希望新增一個環節,那么 Scientist 類需要修改,Visitor  類、XinhuaVisitor 類都需要修改。

有這些多優點,但也有這么多缺點,那實際工作中我們應該怎么判斷是否用訪問者模式呢?總的原則就是揚長避短,即當場景完全利用了訪問者模式的優點,規避了訪問者模式的缺點的時候,就是使用訪問者模式的最佳時機。

雖然使用訪問者模式會讓被訪問者的變更變得更加困難,但如果被訪問者很穩定,基本不會變更,那這個缺點不就去除了么。例如在 ASM 的例子中,元素是  ClassReader,其存儲了字節碼的結構。而字節碼結構完全不會輕易改變,所以在這個「被訪問者的變更變得更加困難」的缺點也就不存在了。

而「類結構變得復雜」這個缺點,則是需要根據當時業務的復雜程度來看的。如果當時業務很簡單,而且變化也不大,那么使用設計模式完全是多余的。但是如果當時業務很復雜了,我們還是在一個類里做修改,那么很大可能性會出大問題。這時候就需要用設計模式來承載復雜的業務結構了。

到此,關于“什么是訪問者模式”的學習就結束了,希望能夠解決大家的疑惑。理論與實踐的搭配能更好的幫助大家學習,快去試試吧!若想繼續學習更多相關知識,請繼續關注億速云網站,小編會繼續努力為大家帶來更多實用的文章!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

凉城县| 赫章县| 新巴尔虎右旗| 商洛市| 肇州县| 龙南县| 高陵县| 出国| 郯城县| 浦江县| 昌平区| 肇庆市| 巴彦县| 科尔| 徐水县| 子长县| 金阳县| 合阳县| 漯河市| 松江区| 株洲县| 六枝特区| 山阳县| 攀枝花市| 宝鸡市| 湘阴县| 黄山市| 唐河县| 临高县| 盐津县| 乳山市| 兴化市| 韩城市| 许昌市| 阜平县| 弥渡县| 新安县| 赞皇县| 博野县| 台州市| 聂荣县|