1. 程式人生 > >JAVA設計模式之 訪問者模式【Visitor Pattern】

JAVA設計模式之 訪問者模式【Visitor Pattern】

一、概述

    訪問者模式是一種較為複雜的行為型設計模式,它包含訪問者和被訪問元素兩個主要組成部分,這些被訪問的元素通常具有不同的型別,且不同的訪問者可以對它們進行不同的訪問操作。在使用訪問者模式時,被訪問元素通常不是單獨存在的,它們儲存在一個集合中,這個集合被稱為“物件結構”,訪問者通過遍歷物件結構實現對其中儲存的元素的逐個操作。訪問者模式是一種物件行為型模式。

二、適用場景

    當有多種型別的訪問者(或是操作者) 對一組被訪問者物件集合(或是物件結構)進行操作(其中物件集合也包含多種型別物件),不同的訪問者型別對每一種具體的被訪問者物件提供不同的訪問操作,每種訪問者型別物件對不同的被訪問者也有不同的訪問操作,那麼這種場景就非常適用訪問者模式。

    如果前面這幾句比較繞的文字說明沒看明白,那麼小呂就舉例一個生活中的業務場景:

    你所在的公司每個月人力資源部要對所有員工進行上班時長、加班時長統計,而財務部要對所有員工進行工資核算,不同職位的員工薪資核算標準肯定不一樣啊,這個大家都明白。在這個案例中人力資源部和財務部是兩個不同型別的部門(訪問者),所有員工(被訪問者)是一個物件集合,而員工又劃分為管理者和技術者兩種型別(備註:這裡小呂只是簡單劃分為兩類),在每月的統計中,人力資源部需要分別對員工進行上班時長和加班時長進行統計,而財務部需要對不同職位的員工進行薪資核算,可見不同部門職責不同,及對員工的訪問操作不同、每個部門對不同型別的員工的訪問操作也不同。那麼針對這種場景  我們有必要了解一下訪問者模式。

三、UML類圖


四、參與者

1>、Visitor(抽象訪問者):為每種具體的被訪問者(ConcreteElement)宣告一個訪問操作;

2>、ConcreteVisitor(具體訪問者):實現對被訪問者(ConcreteElement)的具體訪問操作;

3>、Element(抽象被訪問者):通常有一個Accept方法,用來接收/引用一個抽象訪問者物件;

4>、ConcreteElement(具體被訪問者物件):實現Accept抽象方法,通過傳入的具體訪問者引數、呼叫具體訪問者對該物件的訪問操作方法實現訪問邏輯;

5>、Clent、ObjectStructure(客戶端訪問過程測試環境):該過程中,被訪問者通常為一個集合物件,通過對集合的遍歷完成訪問者對每一個被訪問元素的訪問操作;

五、用例學習

1.抽象被訪問者:公司員工抽象類  Employee.java

/**
 * 公司員工(被訪問者)抽象類
 * @author  [email protected]
 *
 */
public abstract class Employee {
	
	/**
	 * 接收/引用一個抽象訪問者物件
	 * @param department 抽象訪問者 這裡指的是公司部門如 人力資源部、財務部
	 */
	public abstract void accept(Department department);

}
2.具體被訪問者:公司管理崗位員工類 ManagerEmployee.java
/**
 * 公司員工:管理者(具體的被訪問者物件)
 * @author  [email protected]
 * 
 */
public class ManagerEmployee extends Employee {
	// 員工姓名
	private String name;
	// 每天上班時長
	private int timeSheet; 
	// 每月工資
	private double wage;
	// 請假/遲到 懲罰時長
	private int punishmentTime;
	
	public ManagerEmployee(String name, int timeSheet, double wage, int punishmentTime) {
		this.name = name;
		this.timeSheet = timeSheet;
		this.wage = wage;
		this.punishmentTime = punishmentTime;
	}

	
	@Override
	public void accept(Department department) {
		department.visit(this);
	}
	
	
	/**
	 * 獲取每月的上班實際時長 = 每天上班時長 * 每月上班天數 - 懲罰時長
	 * @return
	 */
	public int getTotalTimeSheet(){
		return timeSheet * 22 - punishmentTime;
	}
	
	
	/**
	 * 獲取每月實際應發工資 = 每月固定工資 - 懲罰時長 * 5<br/>
	 * <作為公司管理者 每遲到1小時 扣5塊錢>
	 * @return
	 */
	public double getTotalWage(){
		return wage - punishmentTime * 5;
	}
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getWage() {
		return wage;
	}

	public void setWage(double wage) {
		this.wage = wage;
	}
	
	public int getPunishmentTime() {
		return punishmentTime;
	}

	public void setPunishmentTime(int punishmentTime) {
		this.punishmentTime = punishmentTime;
	}
	
}
3.具體被訪問者:公司普通崗位員工類 GeneralEmployee.java
/**
 * 公司普通員工(具體的被訪問者物件)
 * @author  [email protected]
 *
 */
public class GeneralEmployee extends Employee {
    // 員工姓名
	private String name;
	// 每天上班時長
	private int timeSheet;
	// 每月工資
	private double wage;
	// 請假/遲到 懲罰時長
	private int punishmentTime;

	public GeneralEmployee(String name, int timeSheet, double wage, int punishmentTime) {
		this.name = name;
		this.timeSheet = timeSheet;
		this.wage = wage;
		this.punishmentTime = punishmentTime;
	}

	@Override
	public void accept(Department department) {
		department.visit(this);
	}

	/**
	 * 獲取每月的上班實際時長 = 每天上班時長 * 每月上班天數 - 懲罰時長
	 * @return
	 */
	public int getTotalTimeSheet() {
		return timeSheet * 22 - punishmentTime;
	}

	/**
	 * 獲取每月實際應發工資 = 每月固定工資 - 懲罰時長 * 10<br/>
	 * <作為公司普通員工  每遲到1小時 扣10塊錢  坑吧?  哈哈>
	 * 
	 * @return
	 */
	public double getTotalWage() {
		return wage - punishmentTime * 10;
	}
	
	
	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public double getWage() {
		return wage;
	}

	public void setWage(double wage) {
		this.wage = wage;
	}

	public int getPunishmentTime() {
		return punishmentTime;
	}

	public void setPunishmentTime(int punishmentTime) {
		this.punishmentTime = punishmentTime;
	}

}
4.抽象訪問者:公司部門抽象類 Department.java
/**
 * 公司部門(訪問者)抽象類
 * @author  [email protected]
 *
 */
public abstract class Department {
	
	// 宣告一組過載的訪問方法,用於訪問不同型別的具體元素(這裡指的是不同的員工)  
	
	/**
	 * 抽象方法 訪問公司管理者物件<br/>
	 * 具體訪問物件的什麼  就由具體的訪問者子類(這裡指的是不同的具體部門)去實現
	 * @param me
	 */
	public abstract void visit(ManagerEmployee me);
	
	/**
	 * 抽象方法 訪問公司普通員工物件<br/>
	 * 具體訪問物件的什麼  就由具體的訪問者子類(這裡指的是不同的具體部門)去實現
	 * @param ge
	 */
	public abstract void visit(GeneralEmployee ge);

}
5.具體訪問者:公司財務部類 FADepartment.java
/**
 * 具體訪問者物件:公司財務部<br/>
 * 財務部的職責就是負責統計核算員工的工資
 * @author  [email protected]
 *
 */
public class FADepartment extends Department {

	/**
	 * 訪問公司管理者物件的每月工資
	 */
	@Override
	public void visit(ManagerEmployee me) {
		double totalWage = me.getTotalWage();
		System.out.println("管理者: " + me.getName() + 
				"  固定工資 =" + me.getWage() + 
				", 遲到時長 " + me.getPunishmentTime() + "小時"+
				", 實發工資="+totalWage);
	}

	/**
	 * 訪問公司普通員工物件的每月工資
	 */
	@Override
	public void visit(GeneralEmployee ge) {
		double totalWage = ge.getTotalWage();
		System.out.println("普通員工: " + ge.getName() + 
				"  固定工資 =" + ge.getWage() + 
				", 遲到時長 " + ge.getPunishmentTime() + "小時"+
				", 實發工資="+totalWage);
	}

}
6.具體訪問者:公司人力資源部類 HRDepartment.java
/**
 * 具體訪問者物件:公司人力資源部<br/>
 * 人力資源部的職責就是負責統計核算員工的每月上班時長
 * @author  [email protected]
 *
 */
public class HRDepartment extends Department {

	/**
	 * 訪問公司管理者物件的每月實際上班時長統計
	 */
	@Override
	public void visit(ManagerEmployee me) {
		me.getTotalTimeSheet();
	}

	/**
	 * 訪問公司普通員工物件的每月實際上班時長統計
	 */
	@Override
	public void visit(GeneralEmployee ge) {
		ge.getTotalTimeSheet();
	}

}
7.客戶端測試類:模擬財務部對公司員工的工資核算和訪問 Client.java
import java.util.ArrayList;
import java.util.List;

public class Client {

	public static void main(String[] args) {
		List<Employee> employeeList = new ArrayList<Employee>();
		Employee mep1,mep2,gep1,gep2,gep3;
		// 管理者1
		mep1 = new ManagerEmployee("王總", 8, 20000, 10);
		// 管理者2
		mep2 = new ManagerEmployee("謝經理", 8, 15000, 15);
		// 普通員工1
		gep1 = new GeneralEmployee("小杰", 8, 8000, 8);
		// 普通員工2
		gep2 = new GeneralEmployee("小曉", 8, 8500, 12);
		// 普通員工3
		gep3 = new GeneralEmployee("小虎", 8, 7500, 0);
		
		employeeList.add(mep1);
		employeeList.add(mep2);
		employeeList.add(gep1);
		employeeList.add(gep2);
		employeeList.add(gep3);
		
		// 財務部 對公司員工的工資核算/訪問
		FADepartment department = new FADepartment();
		for(Employee employee : employeeList){
			employee.accept(department);
		}	
	}
	
}

如果要更改為人力資源部對員工的一個月的上班時長統計 則只要將上述程式碼中的

FADepartment department = new FADepartment();
修改為如下即可
HRDepartment department = new HRDepartment();
8.程式執行結果:
管理者: 王總  固定工資 =20000.0, 遲到時長 10小時, 實發工資=19950.0
管理者: 謝經理  固定工資 =15000.0, 遲到時長 15小時, 實發工資=14925.0
普通員工: 小杰  固定工資 =8000.0, 遲到時長 8小時, 實發工資=7920.0
普通員工: 小曉  固定工資 =8500.0, 遲到時長 12小時, 實發工資=8380.0
普通員工: 小虎  固定工資 =7500.0, 遲到時長 0小時, 實發工資=7500.0

六、其他

相關推薦

JAVA設計模式 訪問者模式Visitor Pattern

一、概述     訪問者模式是一種較為複雜的行為型設計模式,它包含訪問者和被訪問元素兩個主要組成部分,這些被訪問的元素通常具有不同的型別,且不同的訪問者可以對它們進行不同的訪問操作。在使用訪問者模式時,被訪問元素通常不是單獨存在的,它們儲存在一個集合中,這個集合被稱為“物

Java設計模式(23)——行為模式訪問者模式

font string 概念 str ron 直接 integer span das 一、概述   概念      作用於某個對象群中各個對象的操作。它可以使你在不改變這些對象本身的情況下,定義作用於這些對象的新操作。   引入   試想這樣一個場景,在一

GOF23設計模式訪問者模式visitor

gpo 也有 模式 訪問者模式 body 不同 nbsp 設計模式 有一個 一、訪問者模式概述   (1)模式動機      對於存儲在一個集合中的對象,他們可能具有不同的類型(即使有一個公共的接口),對於該集合中的對象,可以接受一類稱為訪問者的對象來訪問,不同的訪問者其

設計模式訪問者模式visitor

1、定義 在訪問者模式(Visitor Pattern)中,我們使用了一個訪問者類,它改變了元素類的執行演算法。通過這種方式,元素的執行演算法可以隨著訪問者改變而改變。這種型別的設計模式屬於行為型模式。根據模式,元素物件已接受訪問者物件,這樣訪問者物件就可以處理元素物件上的

設計模式訪問者模式Visitor Pattern

在訪問者模式(Visitor Pattern)中,我們使用了一個訪問者類,它改變了元素類的執行演算法。通過這種方式,元素的執行演算法可以隨著訪問者改變而改變。這種型別的設計模式屬於行為型模式。根據模式,元素物件已接受訪問者物件,這樣訪問者物件就可以處理元素物件上的操作。 意圖:主要將資料結構

15.java設計模式訪問者模式

#### 基本需求: * 電腦需要鍵盤滑鼠等固定的元件組成 * 現在分為個人,組織等去買電腦,而同一種元件對不同的人(訪問者)做出不同的折扣,從而電腦的價格也不一樣 * 傳統的解決方法:在元件內部進行判斷訪問人的型別,從而進行不同打出不同的折扣 * 缺陷:如果訪問者的型別增加了,則需要改變元件內部的判斷

GoF23種設計模式行為型模式訪問者模式

部分 strong 操作 定義 狀態 arraylist his tro 不同的 概述 表示一個作用於某對象結構中的各元素的操作。 它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。 適用性 1.一個對象結構包含很多

Head First設計模式訪問者模式

back visitor 這樣的 耦合 擴展性 表示 accept struct system 一、定義 定義:表示一個作用於某對象結構中的各元素的操作。它使你可以在不改變各元素類的前提下定義作用於這些元素的新操作。 訪問者模式適用於數據結構相對穩定的系統, 它把數據結

C++設計模式訪問者模式

alt bubuko 入口 for art argv ger iter 控制 簡述 訪問者模式(Visitor Pattern)表示一個作用於某對象結構中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用於這些元素的新操作。 代碼實現: // Visitor.c

設計模式的藝術 行為型模式訪問者模式

前言 在公司上班,一般會有兼職或全職的員工,他們都發工資,上同樣的班,但是工資待遇是有區別的,財務部和人事部過來調查處理的手法也不是一樣的,雖然都是一樣的計算工資待遇,在軟體開發中存在著這樣的一種情況,我們需要處理著像員工一樣的集合,集合中的具體物件是不一樣的,去訪問時處理的手段也不一樣,軟體設

設計模式訪問者模式(C++)

設計模式之訪問者模式 訪問者模式,表示一個作用於某物件結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用於這些元素的新操作。訪問者模式適用於資料結構相對穩定的系統。它把資料結構和作用於結構上的操作之間耦合解脫開,使得操作幾何可以相對自由地演化。訪

大話設計模式訪問者模式

訪問者模式: 表示一個 作用於 某物件結構中的各元素的操作,它可以是你在 不改變 各元素的類的前提下定義 作用於這些元素的新操作。 訪問模式適用於:資料結構相對穩定的系統。 他把資料結構和作用於結構上的操作直接的耦合解脫開,使得操作集合可以相對自由地 演化。 訪問者的目的是要

23種設計模式訪問者模式

訪問者模式的定義 定義: 封裝一些作用於某種資料結構中的各元素的操作, 它可以在不改變資料結構的前提下定義作用於這些元素的新的操作 通俗的說, 就是定義一個訪問者角色, 當對指定角色進行訪問時要通過訪問者進行訪問 其類圖如下:   各角色說明: Vistor 抽象訪問

Android設計模式訪問者模式

訪問者模式是一種將資料庫操作與資料結構分離的設計模式。 訪問者模式的基本思想            軟體系統中擁有一個由許多物件構成的、比較穩定的物件結構,這些物件的類都擁有一個accept方法用來接受訪問者物件的訪問。訪問者是一

設計模式訪問者模式

訪問者模式的實現 訪問者模式就是針對不同的資源設定不同的訪問許可權, 反轉這訪問許可權的設定位置,從而達到不修改資源來控制訪問許可權的目的. 先設定一個元素材資源和元訪問許可權 public class unionLevel { public String getLevelName(unio

行為型模式訪問者模式實現

概念 訪問者模式,是行為模式之一,它分離物件的資料和行為,使用Visitor模式,可以不修改已有類的情況下,增加新的操作角色和職責。 角色和職責 抽象訪問者(Visitor)角色:宣告一個或者多個訪問操作,形成所有的具體元素角色必須實現的介面。

java設計模式——策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式訪問者模式、中介者模式、直譯器模式(行為型)讀書筆記

一、策略模式           定義:定義了演算法家族,分別封裝起來,讓他們之間可以互相替換,此模式讓演算法的變化,不會影響到演算法的客戶。           使用場景:策略模式是一種定義一系列演算法的方法,從概念上看,所有的這些演算法完成的都是相同的工作,只是實現不

java設計模式——建造者模式、原型模式(建立性)讀書筆記

一、建造者模式(生成器模式)                 定義:將一個複雜物件的構建和它的表示分離開,使得同樣的構建過程可以得到不同的表示。                 效果:採用建造者模式,使用者只需要選擇建造的型別就可以得到它們,而具體的建造過程和細節就不需要

Java設計模式代理模式

代理模式是Java常見的設計模式之一。所謂代理模式是指客戶端並不直接呼叫實際的物件,而是通過呼叫代理,來間接的呼叫實際的物件。 代理模式的定義: 為其他物件提供一種代理,以控制對這個物件的訪問; 為其他物件提供一種代理以控制對這個物件的訪問。代理物件起到中介作用,可去掉功能

java設計模式模板模式通過LOL選英雄案例

初衷 設計模式(Design Pattern)引用百度百科中的一句話,就是一套被反覆使用、多數人知曉的、經過分類的、程式碼設計經驗的總結。實際上在我們的實際編碼中到處都有設計模式的影子,比如最常用的單例模式,工廠模式,代理模式,觀察者模式等等。其實每種設計模式都