軟體設計模式學習(二十七)訪問者模式

来源:https://www.cnblogs.com/Yee-Q/archive/2020/06/18/13157842.html
-Advertisement-
Play Games

訪問者模式是一種較為複雜的行為型設計模式,它包含訪問者和被訪問元素兩個主要組成部分,這些被訪問的元素具有不同的類型,且不同的訪問者可以對其進行不同的訪問操作 模式動機 對於系統中某些對象,它們存儲在同一個集合中,且具有不同的類型。對於該集合中的對象,可以接受一類稱為訪問者的對象來訪問,不同的訪問者其 ...



訪問者模式是一種較為複雜的行為型設計模式,它包含訪問者和被訪問元素兩個主要組成部分,這些被訪問的元素具有不同的類型,且不同的訪問者可以對其進行不同的訪問操作


模式動機

對於系統中某些對象,它們存儲在同一個集合中,且具有不同的類型。對於該集合中的對象,可以接受一類稱為訪問者的對象來訪問,不同的訪問者其訪問方式有所不同。

在 Java 等面向對象語言中都提供了大量用於存儲多個元素的集合對象,集合中存儲的對象有時候是同一類型,有時候不是同一類型,或許它們只是具有共同的父類。假如我們要針對一個包含不同類型元素的集合採取某種操作,而操作細節根據元素類型不同而不同,就會出現大量類型判斷語句,增大代碼複雜度。

實際使用時,對相同元素的對象也可能存在多種不同的操作方式,而且可能還需要增加新的操作,此時訪問者模式是一個值得考慮的解決方案。


模式定義

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

Represent an operation to be performedd on the elements of an object structure. Visitor lets you define a new operation without changing the classes of the elements on which it operates.


模式分析

訪問者模式結構較為複雜,首先看一張模式結構類圖

對象結構(ObjectStructure)是一個元素集合,存儲了不同類型的元素對象,以供不同訪問者訪問。訪問者模式包括兩個層次,一個是訪問者層次結構,另一個是元素層次結構。

訪問者層次結構提供了抽象訪問者(Visitor)和具體訪問者(ConcreteVisitor)。抽象訪問者聲明瞭訪問元素對象的方法,通常為每一種類型的元素對象都提供一個訪問方法,而具體訪問者可以實現這些訪問方法。

這些訪問方法的設計又有兩種,一種是直接在方法名中標明待訪問元素對象的類型,如 visitConcreteElementA(ConcreteElementA elementA),還有一種是統一取名為 visit(),通過參數類型的不同來定義一系列重載方法。

public abstract class Visitor {
    // 統一取名
    public abstract void visit(ConcreteElementA elementA);
    public abstract void visit(ConcreteElementB elementB);
    // 如果所有訪問者對某一類型的元素訪問操作都相同
    // 則可以將操作代碼移到抽象訪問者中
    public void visit(ConcreteElementC elementC) {
        ...
    }
}

元素層次結構提供了抽象元素類(Element)和具體元素類(ConcreteElementA),抽象元素類一般都聲明一個 accept() 方法,用於接受訪問者的訪問。該方法傳入一個抽象訪問者 Visitor 類型的參數,在程式運行時確定其具體訪問者的類型,並調用具體訪問者對象的 visit() 方法實現對元素對象的操作

public class ConcreteElementA implements Element {
    public void accept(Visitor visitor) {
        visitor.visit(this);
    }
    public void operationA() {
        // 在具體元素類中可以定義不同類型的元素所特有的業務方法
    }
}

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

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

public class ObjectStructure {
    
    private ArrayList list = new ArrayList();
    
    public void accept(Visitor visitor) {
        Iterator i = list.iterator();
        while(i.hashNext()) {
            ((Element)i.next()).accept(visitor);
        }
    }
    
    public void addElement(Element element) {
		list.add(element);
    }
    
    public void removeElement(Element element) {
        list.remove(element);
    }
}

最終在客戶端我們需要實例化一個對象結構對象,並向其添加元素對象,再調用 accept() 方法來接受訪問者對象的訪問。具體訪問者類型可以通過配置文件來確定。

public class Client {
    
    public static void main(String[] args) {
        Element elementA = new ElementA();
        Element elementB = new ElementB();
        Element elementC = new ElementC();
        
        ObjectStructure objectStructure = new ObjectStructure();
        objectStructure.addElement(elementA);
        objectStructure.addElement(elementB);
        objectStructure.addElement(elementC);
        
        Visitor visitor = new ConcreteVisitorA();
        objectStructure.accept(visitor);
    }
}

如果需要修改訪問者類型,只或者增加新的類型的訪問者,只需修改配置文件即可,符合開閉原則。但如果要增加新的類型的具體元素類,則訪問者類需要為其定義新的訪問方法,從這一點看又違背了開閉原則。


模式優缺點

訪問者模式的優點:

  • 使得增加新的訪問操作變得容易,無須修改現有類庫的代碼
  • 將有關類對象的訪問行為i集中到一個訪問者對象中,而不是分散到一個個元素類,類的職責更加清晰
  • 可以跨過類的等級結構訪問不同等級結構的元素類
  • 用戶能夠在不修改現有類層次結構的情況下,定義該類層次結構的新操作

訪問者模式的缺點:

  • 增加新的元素類很困難
  • 訪問者模式要求訪問者對象訪問並調用每一個元素對象的操作,破壞了封裝性


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 面對這麼多的知識點,有的盆友就麻爪了…… 我是誰? 我該從哪裡開始看? 我該怎麼看? 我該看多少? 這,是一個問題。 我們貼心的做了一個學習線路圖: 然並卵,很多人還是一頭霧水…… 我們先對每階段課程做個簡單介紹: PC端頁面製作 學習HTML+CSS搭建網頁、PhotoShop切圖等基礎知識,屬於 ...
  • 前言現在的 Node 對於前端而言可以涵蓋各個方面,包括命令行介面、插件、依賴庫、腳手架以及 Web 服務等。本文是一篇對於 Node 使用的淺談文章,會簡單講解一些個人使用 Node 的經驗,分享的內容主要可分為三個方面: 工具篇 插件篇 服務篇 工具篇會講解使用 NPM 發佈命令行介面的簡單教程 ...
  • 前言 1.本文將從零開始手寫一份vue-next中的響應式原理,出於篇幅和理解的難易程度,我們將只實現核心的api並忽略一些邊界的功能點 本文將實現的api包括 track trigger effect reactive watch computed2.最近很多人私信我問前端問題,博客登陸的少沒及時 ...
  • multipage Github地址 github.com/qinouz/mult…基於 vue-cli4.0 構建 多頁面 模板腳手架! 啟動項目 git clone https://github.com/qinouz/multipage.git cd multipage npm install ...
  • 遇到問題 數據源有數據,但表體無法渲染出數據。 排查問題之路 其實關於layui表格無法渲染的問題之前也遇到過,我知道的情況以下幾種 數據源返回的的格式不正確 (code 必須為 0 ) 正確的返回格式:{"code":0,"msg":"","count":1000,"data":[]} 數據源正確 ...
  • 轉載請註明出處:葡萄城官網,葡萄城為開發者提供專業的開發工具、解決方案和服務,賦能開發者。 原文出處:https://dzone.com/articles/why-masses-are-not-using-latest-css-features-in-20 儘管CSS每年都會發佈全新的特性,但實際上 ...
  • 6.1 webpack概念的引入 在網頁中會引用哪些常見的靜態資源? JS .js、 .jsx 、.coffee、 .ts(TypeScript 類 C# 語言) CSS .css、 .less、 .sass 、.scss Images .jpg 、.png、 .gif 、.bmp 、.svg 字體 ...
  • 常用設計模式思維導圖,大部分設計模式在spring和jdk源碼中都有體現。 在學習spring源碼前,有必要花一定時間瞭解設計模式。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...