JAVA設計模式之 訪問者模式【Visitor Pattern】
一、概述
訪問者模式是一種較為複雜的行為型設計模式,它包含訪問者和被訪問元素兩個主要組成部分,這些被訪問的元素通常具有不同的型別,且不同的訪問者可以對它們進行不同的訪問操作。在使用訪問者模式時,被訪問元素通常不是單獨存在的,它們儲存在一個集合中,這個集合被稱為“物件結構”,訪問者通過遍歷物件結構實現對其中儲存的元素的逐個操作。訪問者模式是一種物件行為型模式。
二、適用場景
當有多種型別的訪問者(或是操作者) 對一組被訪問者物件集合(或是物件結構)進行操作(其中物件集合也包含多種型別物件),不同的訪問者型別對每一種具體的被訪問者物件提供不同的訪問操作,每種訪問者型別物件對不同的被訪問者也有不同的訪問操作,那麼這種場景就非常適用訪問者模式。
如果前面這幾句比較繞的文字說明沒看明白,那麼小呂就舉例一個生活中的業務場景:
你所在的公司每個月人力資源部要對所有員工進行上班時長、加班時長統計,而財務部要對所有員工進行工資核算,不同職位的員工薪資核算標準肯定不一樣啊,這個大家都明白。在這個案例中人力資源部和財務部是兩個不同型別的部門(訪問者),所有員工(被訪問者)是一個物件集合,而員工又劃分為管理者和技術者兩種型別(備註:這裡小呂只是簡單劃分為兩類),在每月的統計中,人力資源部需要分別對員工進行上班時長和加班時長進行統計,而財務部需要對不同職位的員工進行薪資核算,可見不同部門職責不同,及對員工的訪問操作不同、每個部門對不同型別的員工的訪問操作也不同。那麼針對這種場景 我們有必要了解一下訪問者模式。
三、UML類圖
四、參與者
1>、Visitor(抽象訪問者):為每種具體的被訪問者(ConcreteElement)宣告一個訪問操作;
2>、ConcreteVisitor(具體訪問者):實現對被訪問者(ConcreteElement)的具體訪問操作;
3>、Element(抽象被訪問者):通常有一個Accept方法,用來接收/引用一個抽象訪問者物件;
4>、ConcreteElement(具體被訪問者物件):實現Accept抽象方法,通過傳入的具體訪問者引數、呼叫具體訪問者對該物件的訪問操作方法實現訪問邏輯;
5>、Clent、ObjectStructure(客戶端訪問過程測試環境):該過程中,被訪問者通常為一個集合物件,通過對集合的遍歷完成訪問者對每一個被訪問元素的訪問操作;
五、用例學習
1.抽象被訪問者:公司員工抽象類 Employee.java
/**
* 公司員工(被訪問者)抽象類
* @author lvzb.software@qq.com
*
*/
public abstract class Employee {
/**
* 接收/引用一個抽象訪問者物件
* @param department 抽象訪問者 這裡指的是公司部門如 人力資源部、財務部
*/
public abstract void accept(Department department);
}
2.具體被訪問者:公司管理崗位員工類 ManagerEmployee.java
/**
* 公司員工:管理者(具體的被訪問者物件)
* @author lvzb.software@qq.com
*
*/
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 lvzb.software@qq.com
*
*/
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 lvzb.software@qq.com
*
*/
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 lvzb.software@qq.com
*
*/
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 lvzb.software@qq.com
*
*/
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
六、其他
相關文章
- C#設計模式系列:訪問者模式(Visitor)C#設計模式
- 設計模式--訪問者模式Visitor(行為型)設計模式
- JAVA設計模式之訪問者模式Java設計模式
- 設計模式的征途—16.訪問者(Visitor)模式設計模式
- JAVA設計模式之 建造者模式【Builder Pattern】Java設計模式UI
- JAVA設計模式之 中介者模式【Mediator Pattern】Java設計模式
- 15.java設計模式之訪問者模式Java設計模式
- Java設計模式之裝飾者模式(Decorator pattern)Java設計模式
- C++設計模式 - 訪問器模式(Visitor)C++設計模式
- PHP設計模式之訪問者模式PHP設計模式
- 設計模式之觀察者模式(Observer Pattern)設計模式Server
- Java進階篇設計模式之十 ---- 訪問者模式和中介者模式Java設計模式
- 設計模式學習之訪問者模式設計模式
- 【趣味設計模式系列】之【訪問者模式】設計模式
- C#設計模式之訪問者模式C#設計模式
- 23種設計模式之訪問者模式設計模式
- JAVA設計模式之 代理模式【Proxy Pattern】Java設計模式
- 設計模式:訪問者模式設計模式
- 【設計模式】詳解訪問者(Visitor)模式-有多段程式碼出沒設計模式
- 設計模式系列之代理模式(Proxy Pattern)——物件的間接訪問設計模式物件
- JAVA設計模式之 裝飾模式【Decorator Pattern】Java設計模式
- JAVA設計模式之 原型模式【Prototype Pattern】Java設計模式原型
- JAVA設計模式之 狀態模式【State Pattern】Java設計模式
- JAVA設計模式之 命令模式【Command Pattern】Java設計模式
- JAVA設計模式之 迭代器模式【Iterator Pattern】Java設計模式
- 設計模式(十六)——訪問者模式設計模式
- 設計模式--建造者模式(Builder Pattern)設計模式UI
- Java設計模式之單例模式(Singleton Pattern)Java設計模式單例
- JAVA設計模式之 橋接模式【Bridge Pattern】Java設計模式橋接
- JAVA設計模式之 單例模式【Singleton Pattern】Java設計模式單例
- JAVA設計模式之 模板方法模式【Template Method Pattern】Java設計模式
- 極簡設計模式-訪問者模式設計模式
- 設計模式解密(22)- 訪問者模式設計模式解密
- 設計模式之代理模式(proxy pattern)設計模式
- JAVA設計模式之 備忘錄模式【Memento Pattern】Java設計模式
- JAVA設計模式之 工廠方法模式【Factory Method Pattern】Java設計模式
- JAVA設計模式之 抽象工廠模式【Abstract Factory Pattern】Java設計模式抽象
- Net設計模式例項之裝飾者模式(Decorator Pattern)設計模式