設計模式--23、訪問者模式

?

訪問者模式是一種較為復雜的行為型設計模式,它包含訪問者和被訪問元素兩個主要組成部分,這些被訪問的元素通常具有不同的類型,且不同的訪問者可以對它們進行不同的訪問操作。例如處方單中的各種藥品信息就是被訪問的元素,而劃價人員和藥房工作人員就是訪問者。訪問者模式使得用戶可以在不修改現有系統的情況下擴展系統的功能,為這些不同類型的元素增加新的操作。

????? 在使用訪問者模式時,被訪問元素通常不是單獨存在的,它們存儲在一個集合中,這個集合被稱為“對象結構”,訪問者通過遍歷對象結構實現對其中存儲的元素的逐個操作。

????? 訪問者模式定義如下:

訪問者模式(Visitor Pattern):提供一個作用于某對象結構中的各元素的操作表示,它使我們可以在不改變各元素的類的前提下定義作用于這些元素的新操作。訪問者模式是一種對象行為型模式。

????? 訪問者模式的結構較為復雜,其結構如圖26-2所示:

?

?

?

????? 在訪問者模式結構圖中包含如下幾個角色:

????? ●Vistor(抽象訪問者):抽象訪問者為對象結構中每一個具體元素類ConcreteElement聲明一個訪問操作,從這個操作的名稱或參數類型可以清楚知道需要訪問的具體元素的類型,具體訪問者需要實現這些操作方法,定義對這些元素的訪問操作。

????? ●ConcreteVisitor(具體訪問者):具體訪問者實現了每個由抽象訪問者聲明的操作,每一個操作用于訪問對象結構中一種類型的元素。

????? ●Element(抽象元素):抽象元素一般是抽象類或者接口,它定義一個accept()方法,該方法通常以一個抽象訪問者作為參數。【稍后將介紹為什么要這樣設計。】

????? ●ConcreteElement(具體元素):具體元素實現了accept()方法,在accept()方法中調用訪問者的訪問方法以便完成對一個元素的操作。

????? ●?ObjectStructure(對象結構):對象結構是一個元素的集合,它用于存放元素對象,并且提供了遍歷其內部元素的方法。它可以結合組合模式來實現,也可以是一個簡單的集合對象,如一個List對象或一個Set對象。

????? 訪問者模式中對象結構存儲了不同類型的元素對象,以供不同訪問者訪問。訪問者模式包括兩個層次結構,一個是訪問者層次結構,提供了抽象訪問者和具體訪問者,一個是元素層次結構,提供了抽象元素和具體元素。相同的訪問者可以以不同的方式訪問不同的元素,相同的元素可以接受不同訪問者以不同訪問方式訪問。在訪問者模式中,增加新的訪問者無須修改原有系統,系統具有較好的可擴展性。

????? 在訪問者模式中,抽象訪問者定義了訪問元素對象的方法,通常為每一種類型的元素對象都提供一個訪問方法,而具體訪問者可以實現這些訪問方法。這些訪問方法的命名一般有兩種方式:一種是直接在方法名中標明待訪問元素對象的具體類型,如visitElementA(ElementA elementA),還有一種是統一取名為visit(),通過參數類型的不同來定義一系列重載的visit()方法。當然,如果所有的訪問者對某一類型的元素的訪問操作都相同,則可以將操作代碼移到抽象訪問者類中,其典型代碼如下所示:

[java]?view plain?copy
  1. abstract?class?Visitor??
  2. {??
  3. ????public?abstract?void?visit(ConcreteElementA?elementA);??
  4. ????public?abstract?void?visit(ConcreteElementB?elementB);??
  5. ????public?void?visit(ConcreteElementC?elementC)??
  6. ????{??
  7. ????????//元素ConcreteElementC操作代碼??
  8. ????}??
  9. }??

????? 在這里使用了重載visit()方法的方式來定義多個方法用于操作不同類型的元素對象。在抽象訪問者Visitor類的子類ConcreteVisitor中實現了抽象的訪問方法,用于定義對不同類型元素對象的操作,具體訪問者類典型代碼如下所示:

[java]?view plain?copy
  1. class?ConcreteVisitor?extends?Visitor??
  2. {??
  3. ????public?void?visit(ConcreteElementA?elementA)??
  4. ????{??
  5. ????????//元素ConcreteElementA操作代碼??
  6. ????}??
  7. ????public?void?visit(ConcreteElementB?elementB)??
  8. ????{??
  9. ????????//元素ConcreteElementB操作代碼??
  10. ????}??
  11. }??

????? 對于元素類而言,在其中一般都定義了一個accept()方法,用于接受訪問者的訪問,典型的抽象元素類代碼如下所示:

[java]?view plain?copy
  1. interface?Element??
  2. {??
  3. ????public?void?accept(Visitor?visitor);??
  4. }??


????? 需要注意的是該方法傳入了一個抽象訪問者Visitor類型的參數,即針對抽象訪問者進行編程,而不是具體訪問者,在程序運行時再確定具體訪問者的類型,并調用具體訪問者對象的visit()方法實現對元素對象的操作。在抽象元素類Element的子類中實現了accept()方法,用于接受訪問者的訪問,在具體元素類中還可以定義不同類型的元素所特有的業務方法,其典型代碼如下所示:

[java]?view plain?copy
  1. class?ConcreteElementA?implements?Element??
  2. {??
  3. ????public?void?accept(Visitor?visitor)??
  4. ????{??
  5. ????????visitor.visit(this);??
  6. ????}??
  7. ??????
  8. ????public?void?operationA()??
  9. ????{??
  10. ????????//業務方法??
  11. ????}??
  12. }??


????? 在具體元素類ConcreteElementA的accept()方法中,通過調用Visitor類的visit()方法實現對元素的訪問,并以當前對象作為visit()方法的參數。其具體執行過程如下:

????? (1)?調用具體元素類的accept(Visitor visitor)方法,并將Visitor子類對象作為其參數

????? (2)?在具體元素類accept(Visitor visitor)方法內部調用傳入的Visitor對象的visit()方法,如visit(ConcreteElementA elementA),將當前具體元素類對象(this)作為參數,如visitor.visit(this);

????? (3)?執行Visitor對象的visit()方法,在其中還可以調用具體元素對象的業務方法。

????? 這種調用機制也稱為“雙重分派”,正因為使用了雙重分派機制,使得增加新的訪問者無須修改現有類庫代碼,只需將新的訪問者對象作為參數傳入具體元素對象的accept()方法,程序運行時將回調在新增Visitor類中定義的visit()方法,從而增加新的元素訪問方式。

?

思考

雙重分派機制如何用代碼實現?

?


????? 在訪問者模式中,對象結構是一個集合,它用于存儲元素對象并接受訪問者的訪問,其典型代碼如下所示:

[java]?view plain?copy
  1. class?ObjectStructure??
  2. {??
  3. ????private?ArrayList<Element>?list?=?new?ArrayList<Element>();?//定義一個集合用于存儲元素對象??
  4. ??
  5. ????public?void?accept(Visitor?visitor)??
  6. ????{??
  7. ????????Iterator?i=list.iterator();??
  8. ??????????
  9. ????????while(i.hasNext())??
  10. ????????{??
  11. ????????????((Element)i.next()).accept(visitor);?//遍歷訪問集合中的每一個元素??
  12. ????????}??
  13. ????}??
  14. ??
  15. ????public?void?addElement(Element?element)??
  16. ????{??
  17. ????????list.add(element);??
  18. ????}??
  19. ??
  20. ????public?void?removeElement(Element?element)??
  21. ????{??
  22. ????????list.remove(element);??
  23. ????}??
  24. }??


????? 在對象結構中可以使用迭代器對存儲在集合中的元素對象進行遍歷,并逐個調用每一個對象的accept()方法,實現對元素對象的訪問操作。

?

思考

訪問者模式是否符合“開閉原則”?【從增加新的訪問者和增加新的元素兩方面考慮。】

轉載于:https://www.cnblogs.com/snowbook/p/5207835.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/458299.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/458299.shtml
英文地址,請注明出處:http://en.pswp.cn/news/458299.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

C#串口SerialPort常用屬性方法

SerialPort(): //屬性 .BaudRate;獲取或設置波特率 .BytesToRead;得到 接收到數據的字節數 .BytesToWrites;得到送往串口的字節數 .DataBits;獲取或設置數據位 .IsOpen;獲取一個值&#xff0c;判斷串口是否打開 .Pariy;獲取或設置校驗位 .PortName;串口名稱 .ReadBufferSize;獲…

NTFS文件系統的簡述

NTFS文件系統的設計思想基于穩定性、和安全性并支持大容量存儲設備的文件系統&#xff1a;1.它提供日志可以增加文件系統的容錯率&#xff0c;可以有效的保護系統的安全。NTFS是一個可恢復的文件系統。在NTFS分區上即使強制關機后&#xff0c;一般也不需要運行CHKDSK命令修復磁…

Rxjava基礎

現在很多Android App的開發開始使用Rxjava&#xff0c;但是Rxjava以學習曲線陡峭著稱&#xff0c;入門有些困難。經過一段時間的學習和使用&#xff0c;這里來介紹一下我對Rxjava的理解。 說到Rxjava首先需要了解的兩個東西&#xff0c;一個是Observable&#xff08;被觀察者&a…

『協議』XML-RPC 協議規格說明

為什么80%的碼農都做不了架構師&#xff1f;>>> 這篇文章提供所有實現XML-RPC協議所需要的內容。 一覽 XML-RPC是一個工作在因特網上的遠端程序調用&#xff08;Remote Procedure Calling&#xff09;協議。 XML-RPC消息是一個HTTP-POST請求&#xff08;Request&…

Qt之QLineEdit詳解(附源碼)

原博客地址&#xff1a;http://blog.csdn.net/liang19890820/article/details/52044639&#xff0c;感謝原作者總結和分享。 簡述 QLineEdit是一個單行文本輸入框。 QLineEdit允許用戶輸入和編輯單行純文本&#xff0c;提供了很多有用的編輯功能&#xff0c;包括&#xff1a;撤…

POJ 1323 Game Prediction#貪心

(&#xff5e;&#xffe3;▽&#xffe3;)&#xff5e;* //既然是求最少能勝幾次 //說明對方是要盡可能讓我輸 //但為了避免浪費&#xff0c;對方會用比我的牌大的牌中的最小pip的牌來擊敗我 #include<iostream> #include<cstdio> #include<cstring> #inclu…

qt學習之鍵盤事件( keyPressEvent)

//最近一直忙于做驅動&#xff0c;對底層東西很是好奇&#xff0c;好奇鍵盤是 怎么區分每個鍵值的&#xff0c;又是怎么響應的&#xff01;因此&#xff0c;就有了下面這些代碼//環境windows 工具qt 語言c//在主窗體類中聲明鍵盤響應函數 void keyPressEvent(QKeyEvent * event…

C#json數據的序列化和反序列化(將數據轉換為對象或對象集合)

引用 System.Runtime.Serialization.Json 轉載于:https://www.cnblogs.com/a849788087/p/5645828.html

位圖(bmp)文件格式分析

from&#xff1a;https://blog.csdn.net/qingchuwudi/article/details/25785307 位圖(bmp)文件格式分析 作者&#xff1a;深藍&#xff08;由博主分享&#xff09; 一、什么是位圖 計算機能以位圖和矢量圖格式顯示圖像。 1、位圖(Bitmap)&#xff1a; 圖像又稱點陣圖或光…

匯付 支付,痛苦的接入過程

有文檔&#xff0c;但是&#xff0c;寫文檔的人明白&#xff0c;看文檔的人很有難度。 沒有SDK&#xff0c;要自已寫。 然后&#xff0c;錢的流入流出都必須經過虛擬錢包&#xff0c;提現還要綁取現卡&#xff0c;這個我也能理解&#xff0c;不能理解的是&#xff0c;訂單退款&…

隨筆分類 - HALCON學習例程中文詳解

from: https://www.cnblogs.com/chita/category/563492.html隨筆分類 - HALCON學習例程中文詳解HALCON學習例程中文詳解跟我學機器視覺-HALCON學習例程中文詳解-測量圓環腳寬間距摘要: 跟我學機器視覺-HALCON學習例程中文詳解-測量圓環腳寬間距* This example program demonstr…

WinCE6 如何去掉控制面板中的應用?

在WINCE600/PUBLIC/WCESHELLFE/OAK/FILES/wceshellfe.bib把對應的cpl 干掉例如區域設置 好像是2個 ; CESYSGEN IF WCESHELLFE_MODULES_INTLPintlp.cpl $(_FLATRELEASEDIR)/intlp.cpl NK SH ; CESYSGEN ENDIF ; CESYSGEN IF WCESHELLFE_MODULES_INTLLintll.cpl $(_FLATRELEASEDI…

軟件自動更新解決方案及QT實現

from&#xff1a;https://blog.csdn.net/hulinhulin/article/details/46839107軟件自動更新解決放案及QT實現...11 文件的版本控制-XML.22 更新程序的實現...22.1 界面設置...22.2 程序功能...32.2.1 下載網絡數據...32.2.2 XML文件的分析...62.2.3 下載XML文件的DownLoadXML函…

java 基本功 —— 內存相關

2019獨角獸企業重金招聘Python工程師標準>>> 首先我們來說說內存&#xff0c;因為從內存的角度來出發來分析一些變量&#xff0c;引用或者對象的生命周期會更好理解一些。 java是一門編程語言&#xff0c;他跟C有什么不同呢&#xff1f;本質上&#xff0c;他們都是一…

DOM事件處理有三個階段

DOM事件處理有三個階段&#xff1a; 捕捉階段&#xff08;capture phase&#xff09;&#xff1a;從最上層元素&#xff0c;直到最下層&#xff08;你點擊的那個target&#xff09;元素。路過的所有節點都可以捕捉到該事件。命中階段&#xff08;target phase&#xff09;&…

客戶端程序自動更新(升級)的方式

from&#xff1a;https://blog.csdn.net/woaitingting1985/article/details/72954652一、C/S自動更新原理C/S程序自動升級是一個很重要的功能&#xff0c;原理其實很簡單&#xff0c;一般包含兩個程序一個是主程序&#xff0c;也就是除了升級功能以外的程序&#xff0c;另一個就…

怎么用源程序把ChemDraw結構復制到Word文檔

在學習化學過程中&#xff0c;不可避免的會接觸到各種化學結構。這個時候就需要通過繪制化學結構來進行這方面的學習和傳播。ChemDraw Professional 15就可以輔助完成這方面的工作。很多的用戶朋友會通過選中后復制粘貼可以將ChemDraw結構復制到Word文檔中&#xff0c;但這只是…

網絡流(最大流) HDU 1565 方格取數(1) HDU 1569 方格取數(2)

HDU 1565 方格取數(1)給你一個n*n的格子的棋盤&#xff0c;每個格子里面有一個非負數。從中取出若干個數&#xff0c;使得任意的兩個數所在的格子沒有公共邊&#xff0c;就是說所取的數所在的2個格子不能相鄰&#xff0c;并且取出的數的和最大。 Input 包括多個測試實例&#…

python學習 第一篇 基礎

上周報名了reboot python 課程&#xff0c;終于下決心要把python 搞好了&#xff0c;希望自己能堅持下來&#xff0c;并得到自己想要的成績#coding:utf-8 #呵呵 #print hello world #xhello world #print x #xraw_input(hello world) #print x #int #print 23 #print 12*3 #pri…

QT串口編程的相關類(QSerialPortInfo)

QT Serial Port相關的類只有兩個QSerialPortInfo(#include<QSerialPortInfo>) 和QserialPort(#include<QSerialPort>) 先來介紹QSerialPortInfo 1&#xff1a;QSerialPortInfo(#include<QSerialPortInfo>) 該類是一個串口的輔助類類&#xff0c;提供主要是提…