圖解Java設計模式之訪問者模式

来源:https://www.cnblogs.com/haizai/archive/2020/03/29/12593368.html
-Advertisement-
Play Games

圖解Java設計模式之訪問者模式 測試系統的需求 傳統方式的問題分析 訪問者模式基本介紹 訪問者模式應用實例 訪問者模式的註意事項和細節 測試系統的需求 1)將人分為男人和女人,對歌手進行測評,看完某個歌手錶演後,得到他們對該歌手的不同評價(評價有不同的種類,比如成功、失敗等)2)傳統方案 傳統方式 ...


圖解Java設計模式之訪問者模式

 

測試系統的需求

1)將人分為男人和女人,對歌手進行測評,看完某個歌手錶演後,得到他們對該歌手的不同評價(評價有不同的種類,比如成功、失敗等)
2)傳統方案
在這裡插入圖片描述

傳統方式的問題分析

1)如果系統比較小,沒有問題,但是考慮系統增加越來越多的新的功能時,對代碼改動比較大,違反類ocp原則,不利於維護。
2)擴展性不好,比如增加類新的人員類型,或者管理方法。

訪問者模式基本介紹

1)訪問者模式(Visitor Pattern),封裝一些作用於某種數據結構的各元素的操作,它可以在不改變數據結構的前提下定義作用於這些元素的新的操作。
2)主要將數據結構與數據操作分離,解決數據結構和操作耦合性問題
3)訪問者模式的基本工作原理是 :在被訪問的類裡面加一個對外提供接待訪問者的介面
4)訪問者模式主要應用場景是 :需要對一個對象結構中的對象進行很多不同操作(這些操作彼此沒有關聯),同時需要避免讓這些操作“污染”這些對象的類,可以選用訪問者模式解決。
在這裡插入圖片描述
說明 :
1)Visitor 是抽象訪問者,為該對象結構中的ConcreteElement的每一個類聲明一個visit操作。
2)ConcreteVisitor :是一個具體的訪問值,實現每個有Visitor 聲明的操作,是每個操作實現的部分。
3)ObjectStructure 能枚舉它的元素,可以提供一個高層的介面,用來允許訪問者訪問元素。
4)Element 定義一個accept方法,接收一個訪問者對象。
5)ConcreteElement 為具體元素,實現類accept方法。

訪問者模式應用實例

在這裡插入圖片描述

package com.example.demo.visitor;

import javax.activation.MailcapCommandMap;

public abstract class Action {
	
	/**
	 * 得到男性的測評
	 * @param man
	 */
	public abstract void getManResult(Man man);
	
	/**
	 * 得到女的測評
	 * @param woman
	 */
	public abstract void getWomanResult(Woman woman);

}
package com.example.demo.visitor;

public class Fail extends Action{

	@Override
	public void getManResult(Man man) {
		// TODO Auto-generated method stub
		System.out.println(" 男人給的評價該歌手很失敗 ! ");
	}

	@Override
	public void getWomanResult(Woman woman) {
		// TODO Auto-generated method stub
		System.out.println(" 女人給的評價該歌手很失敗 ! ");
	}

}
package com.example.demo.visitor;

public class Success extends Action{

	@Override
	public void getManResult(Man man) {
		// TODO Auto-generated method stub
		System.out.println(" 男人給的評價該歌手很成功 ! ");
	}

	@Override
	public void getWomanResult(Woman woman) {
		// TODO Auto-generated method stub
		System.out.println(" 女人給的評價該歌手很成功 ! ");
	}

}
package com.example.demo.visitor;

public abstract class Person {
	
	public abstract void accept(Action action);
}
package com.example.demo.visitor;

public class Man extends Person {

	@Override
	public void accept(Action action) {
		// TODO Auto-generated method stub
		action.getManResult(this);
	}

}
package com.example.demo.visitor;

/**
 * 說明
 * 1. 這裡我們使用到了雙分派,即首先在客戶端程式中,將具體狀態作為參數傳遞Woman中(第一次分派)
 * 2. 然後Woman 類調用作為參數的 “具體方法” 中方法getWomanResult,同時將自己(this)作為參數傳入,完成第二次的分派
 * @author zhaozhaohai
 *
 */
public class Woman extends Person {

	@Override
	public void accept(Action action) {
		// TODO Auto-generated method stub
		action.getWomanResult(this);
	}

}
package com.example.demo.visitor;

import java.util.LinkedList;
import java.util.List;

/**
 * 數據結構,管理很多人(Man,Woman)
 * @author zhaozhaohai
 *
 */
public class ObjectStructure {

	/**
	 * 維護一個集合
	 */
	private List<Person> persons = new LinkedList<Person>();
	
	/**
	 * 增加到list
	 * @param person
	 */
	public void attach(Person person) {
		persons.add(person);
	}
	
	/**
	 * 移除
	 * @param person
	 */
	public void detach(Person person) {
		persons.remove(person);
	}
	
	/**
	 * 顯示測試情況
	 * @param action
	 */
	public void display(Action action) {
		for (Person person : persons) {
			person.accept(action);
		}
	}
}
package com.example.demo.visitor;

public class Wait extends Action{

	@Override
	public void getManResult(Man man) {
		// TODO Auto-generated method stub
		System.out.println(" 男人給的評價是該歌手待定。。 ");
	}

	@Override
	public void getWomanResult(Woman woman) {
		// TODO Auto-generated method stub
		System.out.println(" 女人給的評價是該歌手待定。。 ");
	}

}
package com.example.demo.visitor;

public class Client {

	public static void main(String[] args) {
		// TODO Auto-generated method stub
		// 創建ObjectStructure
		ObjectStructure objectStructure = new ObjectStructure();
		objectStructure.attach(new Man());
		objectStructure.attach(new Woman());
		
		// 成功
		Success success = new Success();
		objectStructure.display(success);
		System.out.println("-------------------");
		// 失敗
		Fail fail = new Fail();
		objectStructure.display(fail);
		System.out.println("----------給的是待定的測評------------");
		Wait wait = new Wait();
		objectStructure.display(wait);
	}

}

小結 - 雙分派
上面提到雙分派,所謂雙分派是指不管類怎麼變化,我們都能找到期望的方法運行。雙分派意味著得到執行的操作取決於請求的種類和兩個接收者的類型。
假設要添加一個Wait的狀態類,考察Man類和Woman類的反應,由於使用了雙分派,只需增加一個Action子類即可在客戶端調用即可,不需要改動任何其他類的代碼。
![在這裡插入圖片描述](https://img-blog.csdnimg.cn/20200328211428620.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poYW8xMjk5MDAyNzg4,size_16,color_FFFFFF,t_

訪問者模式的註意事項和細節

優點 :
1)訪問者模式符合單一職責原則,讓程式具有優秀的擴展性和靈活性非常高。
2)訪問者模式可以對功能進行統一,可以做報表、UI、攔截器與過濾器,適用於數據結構相對穩定的系統。
缺點 :
1)具體元素對訪問者公佈細節,也就是說訪問者關註類其他類的內部細節,這是迪米特法則所不建議的,這樣造成類具體元素變更比較困難。
2)違背類依賴導致原則,訪問者依賴的是具體元素,而不是抽象元素。
3)因此,如果一個系統有比較穩定的數據結構,又有經常變化的功能需求,那麼訪問者模式就是比較合適的。


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

-Advertisement-
Play Games
更多相關文章
  • 1、ThymeLeaf+LayUI表格渲染錯誤 使用thymeleafhe+layui渲染表格時,出現錯誤org.thymeleaf.exceptions.TemplateProcessingException: Could not parse as expression: 這是因為[[]]是thy ...
  • 將指定數字插入到數組的末尾,返回值為 將數組的第一個元素刪除並返回,返回值為 ...
  • 簡單繼承: @extend 繼承 編譯後 關聯屬性繼承: 編譯後 鏈式繼承: 編譯後 偽類繼承: 編譯後 sass嵌套 編譯後 相同的屬性值首碼,也可以用嵌套 編譯後 sass條件控制 @if @else if @else 編譯後 條件判斷語句也可以寫在外面 編譯後 迴圈 @for $i from ...
  • 對前端稍微有點瞭解的初學者都知道,JavaScript是必不可少的工具。毫不誇張的說,大部分網頁都使用了JavaScript,想要成為一個優秀的前端工程師,做出漂亮令用戶滿意的網頁,熟練掌握JavaScript是一個必備技能。本文為新手整理了一篇JavaScript基礎教程入門指南,希望可以幫助編程 ...
  • number類型 編譯後 color類型: 編譯後 string類型 編譯後 list數組類型 nth(list, num) 獲取list數組中的下標為num的元素 註意num下標是從1開始的 編譯後 index(list, str) 返回str在list數組中的下標 編譯後 map 數組類型(有點 ...
  • 當網路中兩個進程需要通信時,我們往往會使用 來實現。 都不陌生。當三次握手成功後,客戶端與服務端就能通信,並且,彼此之間通信的數據包格式都是二進位,由 協議負責傳輸。 當客戶端和服務端取得了二進位數據包後,我們往往需要『萃取』出想要的數據,這樣才能更好的執行業務邏輯。所以,我們需要定義好數據結構來描 ...
  • 腳本的生成過程 添加模板的時候生成script,商家添加商品的時候拷貝相應的script到sku中。 更新運費模板的時候,發消息到消費者,批量更新相關sku的模板信息。 計算過程 緩存數據結構 script和模板id作為sku的一部分存儲是為了計算使用相同模板的sku的總價。 腳本示例 functi ...
  • 圖解Java設計模式之迭代器模式 看一個具體的需求 傳統的方式的問題分析 迭代器模式基本介紹 迭代器模式的原理類圖 迭代器模式應用實例 迭代器模式在JDK - ArrayList 集合應用的源碼分析 迭代器模式的註意事項和細節 看一個具體的需求 編寫程式展示一個學校院繫結構 :需求是這樣,要在一個頁 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...