Java設計模式之訪問者模式

一·訪問者模式

         訪問者模式表示一個作用於某對象結構中的各元素的操作,它使你可以在不改變各元素類的前提下定義作用於這些元素的新操作。
從定義可以看出結構對象是使用訪問者模式的必備條件,而且這個結構對象必須存在遍歷自身各個對象的方法,類似於Java中的Collection。

     訪問者模式的目的是要把處理從數據結構中分離出來,如果系統有比較穩定的數據結構,又有易於變化的算法的話,使用訪問者模式是個不錯的選擇,因爲訪問者模式使的算法操作的增加變得容易。相反,如果系統的數據結構不穩定,易於變化,則此係統就不適合使用訪問者模式了。

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


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

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

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

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

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

用例學習

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

  1. /** 
  2.  * 公司員工(被訪問者)抽象類 
  3.  * @author  [email protected] 
  4.  * 
  5.  */  
  6. public abstract class Employee {  
  7.       
  8.     /** 
  9.      * 接收/引用一個抽象訪問者對象 
  10.      * @param department 抽象訪問者 這裏指的是公司部門如 人力資源部、財務部 
  11.      */  
  12.     public abstract void accept(Department department);  
  13.   
  14. }  
2.具體被訪問者:公司管理崗位員工類 ManagerEmployee.java
  1. /** 
  2.  * 公司員工:管理者(具體的被訪問者對象) 
  3.  * @author  [email protected] 
  4.  *  
  5.  */  
  6. public class ManagerEmployee extends Employee {  
  7.     // 員工姓名  
  8.     private String name;  
  9.     // 每天上班時長  
  10.     private int timeSheet;   
  11.     // 每月工資  
  12.     private double wage;  
  13.     // 請假/遲到 懲罰時長  
  14.     private int punishmentTime;  
  15.       
  16.     public ManagerEmployee(String name, int timeSheet, double wage, int punishmentTime) {  
  17.         this.name = name;  
  18.         this.timeSheet = timeSheet;  
  19.         this.wage = wage;  
  20.         this.punishmentTime = punishmentTime;  
  21.     }  
  22.   
  23.       
  24.     @Override  
  25.     public void accept(Department department) {  
  26.         department.visit(this);  
  27.     }  
  28.       
  29.       
  30.     /** 
  31.      * 獲取每月的上班實際時長 = 每天上班時長 * 每月上班天數 - 懲罰時長 
  32.      * @return 
  33.      */  
  34.     public int getTotalTimeSheet(){  
  35.         return timeSheet * 22 - punishmentTime;  
  36.     }  
  37.       
  38.       
  39.     /** 
  40.      * 獲取每月實際應發工資 = 每月固定工資 - 懲罰時長 * 5<br/> 
  41.      * <作爲公司管理者 每遲到1小時 扣5塊錢> 
  42.      * @return 
  43.      */  
  44.     public double getTotalWage(){  
  45.         return wage - punishmentTime * 5;  
  46.     }  
  47.       
  48.     public String getName() {  
  49.         return name;  
  50.     }  
  51.   
  52.     public void setName(String name) {  
  53.         this.name = name;  
  54.     }  
  55.   
  56.     public double getWage() {  
  57.         return wage;  
  58.     }  
  59.   
  60.     public void setWage(double wage) {  
  61.         this.wage = wage;  
  62.     }  
  63.       
  64.     public int getPunishmentTime() {  
  65.         return punishmentTime;  
  66.     }  
  67.   
  68.     public void setPunishmentTime(int punishmentTime) {  
  69.         this.punishmentTime = punishmentTime;  
  70.     }  
  71.       
  72. }  
3.具體被訪問者:公司普通崗位員工類 GeneralEmployee.java
  1. /** 
  2.  * 公司普通員工(具體的被訪問者對象) 
  3.  * @author  [email protected] 
  4.  * 
  5.  */  
  6. public class GeneralEmployee extends Employee {  
  7.     // 員工姓名  
  8.     private String name;  
  9.     // 每天上班時長  
  10.     private int timeSheet;  
  11.     // 每月工資  
  12.     private double wage;  
  13.     // 請假/遲到 懲罰時長  
  14.     private int punishmentTime;  
  15.   
  16.     public GeneralEmployee(String name, int timeSheet, double wage, int punishmentTime) {  
  17.         this.name = name;  
  18.         this.timeSheet = timeSheet;  
  19.         this.wage = wage;  
  20.         this.punishmentTime = punishmentTime;  
  21.     }  
  22.   
  23.     @Override  
  24.     public void accept(Department department) {  
  25.         department.visit(this);  
  26.     }  
  27.   
  28.     /** 
  29.      * 獲取每月的上班實際時長 = 每天上班時長 * 每月上班天數 - 懲罰時長 
  30.      * @return 
  31.      */  
  32.     public int getTotalTimeSheet() {  
  33.         return timeSheet * 22 - punishmentTime;  
  34.     }  
  35.   
  36.     /** 
  37.      * 獲取每月實際應發工資 = 每月固定工資 - 懲罰時長 * 10<br/> 
  38.      * <作爲公司普通員工  每遲到1小時 扣10塊錢  坑吧?  哈哈> 
  39.      *  
  40.      * @return 
  41.      */  
  42.     public double getTotalWage() {  
  43.         return wage - punishmentTime * 10;  
  44.     }  
  45.       
  46.       
  47.     public String getName() {  
  48.         return name;  
  49.     }  
  50.   
  51.     public void setName(String name) {  
  52.         this.name = name;  
  53.     }  
  54.   
  55.     public double getWage() {  
  56.         return wage;  
  57.     }  
  58.   
  59.     public void setWage(double wage) {  
  60.         this.wage = wage;  
  61.     }  
  62.   
  63.     public int getPunishmentTime() {  
  64.         return punishmentTime;  
  65.     }  
  66.   
  67.     public void setPunishmentTime(int punishmentTime) {  
  68.         this.punishmentTime = punishmentTime;  
  69.     }  
  70.   
  71. }  
4.抽象訪問者:公司部門抽象類 Department.java
  1. /** 
  2.  * 公司部門(訪問者)抽象類 
  3.  * @author  [email protected] 
  4.  * 
  5.  */  
  6. public abstract class Department {  
  7.       
  8.     // 聲明一組重載的訪問方法,用於訪問不同類型的具體元素(這裏指的是不同的員工)    
  9.       
  10.     /** 
  11.      * 抽象方法 訪問公司管理者對象<br/> 
  12.      * 具體訪問對象的什麼  就由具體的訪問者子類(這裏指的是不同的具體部門)去實現 
  13.      * @param me 
  14.      */  
  15.     public abstract void visit(ManagerEmployee me);  
  16.       
  17.     /** 
  18.      * 抽象方法 訪問公司普通員工對象<br/> 
  19.      * 具體訪問對象的什麼  就由具體的訪問者子類(這裏指的是不同的具體部門)去實現 
  20.      * @param ge 
  21.      */  
  22.     public abstract void visit(GeneralEmployee ge);  
  23.   
  24. }  
5.具體訪問者:公司財務部類 FADepartment.java
  1. /** 
  2.  * 具體訪問者對象:公司財務部<br/> 
  3.  * 財務部的職責就是負責統計覈算員工的工資 
  4.  * @author  [email protected] 
  5.  * 
  6.  */  
  7. public class FADepartment extends Department {  
  8.   
  9.     /** 
  10.      * 訪問公司管理者對象的每月工資 
  11.      */  
  12.     @Override  
  13.     public void visit(ManagerEmployee me) {  
  14.         double totalWage = me.getTotalWage();  
  15.         System.out.println("管理者: " + me.getName() +   
  16.                 "  固定工資 =" + me.getWage() +   
  17.                 ", 遲到時長 " + me.getPunishmentTime() + "小時"+  
  18.                 ", 實發工資="+totalWage);  
  19.     }  
  20.   
  21.     /** 
  22.      * 訪問公司普通員工對象的每月工資 
  23.      */  
  24.     @Override  
  25.     public void visit(GeneralEmployee ge) {  
  26.         double totalWage = ge.getTotalWage();  
  27.         System.out.println("普通員工: " + ge.getName() +   
  28.                 "  固定工資 =" + ge.getWage() +   
  29.                 ", 遲到時長 " + ge.getPunishmentTime() + "小時"+  
  30.                 ", 實發工資="+totalWage);  
  31.     }  
  32.   
  33. }  
6.具體訪問者:公司人力資源部類 HRDepartment.java
  1. /** 
  2.  * 具體訪問者對象:公司人力資源部<br/> 
  3.  * 人力資源部的職責就是負責統計覈算員工的每月上班時長 
  4.  * @author  [email protected] 
  5.  * 
  6.  */  
  7. public class HRDepartment extends Department {  
  8.   
  9.     /** 
  10.      * 訪問公司管理者對象的每月實際上班時長統計 
  11.      */  
  12.     @Override  
  13.     public void visit(ManagerEmployee me) {  
  14.         me.getTotalTimeSheet();  
  15.     }  
  16.   
  17.     /** 
  18.      * 訪問公司普通員工對象的每月實際上班時長統計 
  19.      */  
  20.     @Override  
  21.     public void visit(GeneralEmployee ge) {  
  22.         ge.getTotalTimeSheet();  
  23.     }  
  24.   
  25. }  
7.客戶端測試類:模擬財務部對公司員工的工資覈算和訪問 Client.java
  1. import java.util.ArrayList;  
  2. import java.util.List;  
  3.   
  4. public class Client {  
  5.   
  6.     public static void main(String[] args) {  
  7.         List<Employee> employeeList = new ArrayList<Employee>();  
  8.         Employee mep1,mep2,gep1,gep2,gep3;  
  9.         // 管理者1  
  10.         mep1 = new ManagerEmployee("王總"82000010);  
  11.         // 管理者2  
  12.         mep2 = new ManagerEmployee("謝經理"81500015);  
  13.         // 普通員工1  
  14.         gep1 = new GeneralEmployee("小杰"880008);  
  15.         // 普通員工2  
  16.         gep2 = new GeneralEmployee("小曉"8850012);  
  17.         // 普通員工3  
  18.         gep3 = new GeneralEmployee("小虎"875000);  
  19.           
  20.         employeeList.add(mep1);  
  21.         employeeList.add(mep2);  
  22.         employeeList.add(gep1);  
  23.         employeeList.add(gep2);  
  24.         employeeList.add(gep3);  
  25.           
  26.         // 財務部 對公司員工的工資覈算/訪問  
  27.         FADepartment department = new FADepartment();  
  28.         for(Employee employee : employeeList){  
  29.             employee.accept(department);  
  30.         }     
  31.     }  
  32.       
  33. }  

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

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


原文出處的地方是  http://blog.csdn.net/janice0529/article/details/41151987點擊打開鏈接















發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章