1. 程式人生 > >操作複雜物件結構——訪問者模式(三)

操作複雜物件結構——訪問者模式(三)

26.3 完整解決方案

      Sunny軟體公司開發人員使用訪問者模式對OA系統中員工資料彙總模組進行重構,使得系統可以很方便地增加新型別的訪問者,更加符合“單一職責原則”和“開閉原則”,重構後的基本結構如圖26-3所示:

       在圖26-3中,FADepartment表示財務部,HRDepartment表示人力資源部,它們充當具體訪問者角色,其抽象父類Department充當抽象訪問者角色;EmployeeList充當物件結構,用於儲存員工列表;FulltimeEmployee表示正式員工,ParttimeEmployee表示臨時工,它們充當具體元素角色,其父介面Employee
充當抽象元素角色。完整程式碼如下所示:
import java.util.*;

//員工類:抽象元素類
interface Employee
{
	public void accept(Department handler); //接受一個抽象訪問者訪問
}

//全職員工類:具體元素類
class FulltimeEmployee implements Employee
{
	private String name;
	private double weeklyWage;
	private int workTime;

	public FulltimeEmployee(String name,double weeklyWage,int workTime)
	{
		this.name = name;
		this.weeklyWage = weeklyWage;
		this.workTime = workTime;
	}	

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

	public void setWeeklyWage(double weeklyWage) 
    {
		this.weeklyWage = weeklyWage; 
	}

	public void setWorkTime(int workTime) 
    {
		this.workTime = workTime; 
	}

	public String getName() 
    {
		return (this.name); 
	}

	public double getWeeklyWage() 
    {
		return (this.weeklyWage); 
	}

	public int getWorkTime() 
    {
		return (this.workTime); 
	}

	public void accept(Department handler)
    {
		handler.visit(this); //呼叫訪問者的訪問方法
	}
}

//兼職員工類:具體元素類
class ParttimeEmployee implements Employee
{
	private String name;
	private double hourWage;
	private int workTime;

	public ParttimeEmployee(String name,double hourWage,int workTime)
	{
		this.name = name;
		this.hourWage = hourWage;
		this.workTime = workTime;
	}	

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

	public void setHourWage(double hourWage) 
    {
		this.hourWage = hourWage; 
	}

	public void setWorkTime(int workTime) 
    {
		this.workTime = workTime; 
	}

	public String getName() 
    {
		return (this.name); 
	}

	public double getHourWage() 
    {
		return (this.hourWage); 
	}

	public int getWorkTime() 
    {
		return (this.workTime); 
	}

	public void accept(Department handler)
    {
		handler.visit(this); //呼叫訪問者的訪問方法
	}
}

//部門類:抽象訪問者類
abstract class Department
{
    //宣告一組過載的訪問方法,用於訪問不同型別的具體元素
	public abstract void visit(FulltimeEmployee employee);
	public abstract void visit(ParttimeEmployee employee);	
}

//財務部類:具體訪問者類
class FADepartment extends Department
{
    //實現財務部對全職員工的訪問
	public void visit(FulltimeEmployee employee)
	{
		int workTime = employee.getWorkTime();
		double weekWage = employee.getWeeklyWage();
		if(workTime > 40)
		{
			weekWage = weekWage + (workTime - 40) * 100;
		}
		else if(workTime < 40)
		{
			weekWage = weekWage - (40 - workTime) * 80;
			if(weekWage < 0)
			{
				weekWage = 0;
			}
		}
		System.out.println("正式員工" + employee.getName() + "實際工資為:" + weekWage + "元。");			
	}

    //實現財務部對兼職員工的訪問
	public void visit(ParttimeEmployee employee)
	{
		int workTime = employee.getWorkTime();
		double hourWage = employee.getHourWage();
		System.out.println("臨時工" + employee.getName() + "實際工資為:" + workTime * hourWage + "元。");		
	}		
}

//人力資源部類:具體訪問者類
class HRDepartment extends Department
{
    //實現人力資源部對全職員工的訪問
	public void visit(FulltimeEmployee employee)
	{
		int workTime = employee.getWorkTime();
		System.out.println("正式員工" + employee.getName() + "實際工作時間為:" + workTime + "小時。");
		if(workTime > 40)
		{
			System.out.println("正式員工" + employee.getName() + "加班時間為:" + (workTime - 40) + "小時。");
		}
		else if(workTime < 40)
		{
			System.out.println("正式員工" + employee.getName() + "請假時間為:" + (40 - workTime) + "小時。");
		}						
	}

    //實現人力資源部對兼職員工的訪問
	public void visit(ParttimeEmployee employee)
	{
		int workTime = employee.getWorkTime();
		System.out.println("臨時工" + employee.getName() + "實際工作時間為:" + workTime + "小時。");
	}		
}

//員工列表類:物件結構
class EmployeeList
{
    //定義一個集合用於儲存員工物件
	private ArrayList<Employee> list = new ArrayList<Employee>();

	public void addEmployee(Employee employee)
	{
		list.add(employee);
	}

    //遍歷訪問員工集合中的每一個員工物件
	public void accept(Department handler)
	{
		for(Object obj : list)
		{
			((Employee)obj).accept(handler);
		}
	}
}

      為了提高系統的靈活性和可擴充套件性,我們將具體訪問者類的類名儲存在配置檔案中,並通過工具類XMLUtil來讀取配置檔案並反射生成物件,XMLUtil類的程式碼如下所示:

import javax.xml.parsers.*;
import org.w3c.dom.*;
import org.xml.sax.SAXException;
import java.io.*;
class XMLUtil
{
    //該方法用於從XML配置檔案中提取具體類類名,並返回一個例項物件
    public static Object getBean()
    {
		try
		{
			//建立文件物件
			DocumentBuilderFactory dFactory = DocumentBuilderFactory.newInstance();
			DocumentBuilder builder = dFactory.newDocumentBuilder();
			Document doc;							
			doc = builder.parse(new File("config.xml")); 
		
			//獲取包含類名的文字節點
			NodeList nl = doc.getElementsByTagName("className");
            Node classNode=nl.item(0).getFirstChild();
            String cName=classNode.getNodeValue();
            
            //通過類名生成例項物件並將其返回
            Class c=Class.forName(cName);
	  	    Object obj=c.newInstance();
            return obj;
        }   
        catch(Exception e)
        {
           	e.printStackTrace();
           	return null;
       	}
    }
}

       配置檔案config.xml中儲存了具體訪問者類的類名,程式碼如下所示:

<?xml version="1.0"?>
<config>
	<className>FADepartment</className>
</config>

     編寫如下客戶端測試程式碼:

class Client
{
	public static void main(String args[])
	{
		EmployeeList list = new EmployeeList();
		Employee fte1,fte2,fte3,pte1,pte2;

		fte1 = new FulltimeEmployee("張無忌",3200.00,45);
		fte2 = new FulltimeEmployee("楊過",2000.00,40);
		fte3 = new FulltimeEmployee("段譽",2400.00,38);
		pte1 = new ParttimeEmployee("洪七公",80.00,20);
		pte2 = new ParttimeEmployee("郭靖",60.00,18);

		list.addEmployee(fte1);
		list.addEmployee(fte2);
		list.addEmployee(fte3);
		list.addEmployee(pte1);
		list.addEmployee(pte2);

		Department dep;
		dep = (Department)XMLUtil.getBean();
		list.accept(dep);
	}
}

      編譯並執行程式,輸出結果如下:

正式員工張無忌實際工資為:3700.0元。

正式員工楊過實際工資為:2000.0元。

正式員工段譽實際工資為:2240.0元。

臨時工洪七公實際工資為:1600.0元。

臨時工郭靖實際工資為:1080.0元。

      如果需要更換具體訪問者類,無須修改原始碼,只需修改配置檔案,例如將訪問者類由財務部改為人力資源部,只需將儲存在配置檔案中的具體訪問者類FADepartment改為HRDepartment,如下程式碼所示:

<?xml version="1.0"?>
<config>
    <className>HRDepartment</className>
</config>

      重新執行客戶端程式,輸出結果如下:

正式員工張無忌實際工作時間為:45小時。

正式員工張無忌加班時間為:5小時。

正式員工楊過實際工作時間為:40小時。

正式員工段譽實際工作時間為:38小時。

正式員工段譽請假時間為:2小時。

臨時工洪七公實際工作時間為:20小時。

臨時工郭靖實際工作時間為:18小時。

      如果要在系統中增加一種新的訪問者,無須修改原始碼,只要增加一個新的具體訪問者類即可,在該具體訪問者中封裝了新的操作元素物件的方法。從增加新的訪問者的角度來看,訪問者模式符合“開閉原則”。

      如果要在系統中增加一種新的具體元素,例如增加一種新的員工型別為“退休人員”,由於原有系統並未提供相應的訪問介面(在抽象訪問者中沒有宣告任何訪問“退休人員”的方法),因此必須對原有系統進行修改,在原有的抽象訪問者類和具體訪問者類中增加相應的訪問方法。從增加新的元素的角度來看,訪問者模式違背了“開閉原則”。

      綜上所述,訪問者模式與抽象工廠模式類似,對“開閉原則”的支援具有傾斜性,可以很方便地新增新的訪問者,但是新增新的元素較為麻煩。

相關推薦

操作複雜物件結構——訪問者模式

26.3 完整解決方案       Sunny軟體公司開發人員使用訪問者模式對OA系統中員工資料彙總模組進行重構,使得系統可以很方便地增加新型別的訪問者,更加符合“單一職責原則”和“開閉原則”,重構後的基本結構如圖26-3所示:        在圖26-3中,FADepa

操作複雜物件結構——訪問者模式

26.4 訪問者模式與組合模式聯用       在訪問者模式中,包含一個用於儲存元素物件集合的物件結構,我們通常可以使用迭代器來遍歷物件結構,同時具體元素之間可以存在整體與部分關係,有些元素作為容器物

操作複雜物件結構——訪問者模式

想必大家都去過醫院,雖然沒有人喜歡去醫院(愛崗敬業的醫務工作人員除外,)。在醫生開具處方單(藥單)後,很多醫院都存在如下處理流程:劃價人員拿到處方單之後根據藥品名稱和數量計算總價,藥房工作人員根據藥品名稱和數量準備藥品,如圖26-1所示:       在圖26-1中,

複雜物件的組裝與建立——建造者模式

8.4 關於Director的進一步討論 指揮者類Director在建造者模式中扮演非常重要的作用,簡單的Director類用於指導具體建造者如何構建產品,它按一定次序呼叫Builder的build

建造者模式-Builder Pattern 複雜物件的組裝與建立——建造者模式:關於Director的進一步討論,建造者模式總結

8.4 關於Director的進一步討論 指揮者類Director在建造者模式中扮演非常重要的作用,簡單的Director類用於指導具體建造者如何構建產品,它按一定次序呼叫Builder的build

不相容結構的協調——介面卡模式

分享一下我老師大神的人工智慧教程!零基礎,通俗易懂!http://blog.csdn.net/jiangjunshow 也歡迎大家轉載本篇文章。分享知識,造福人民,實現我們中華民族偉大復興!        

物件間的聯動——觀察者模式

23.3 完整解決方案       為了實現物件之間的聯動,Sunny軟體公司開發人員決定使用觀察者模式來進行多人聯機對戰遊戲的設計,其基本結構如圖22-4所示: 圖22-4  多人聯機對戰遊戲結構圖       在圖22-4中,AllyControlCenter充當目

協調多個物件之間的互動——中介者模式

20.3 完整解決方案      為了協調介面元件物件之間的複雜互動關係,Sunny公司開發人員使用中介者模式來設計客戶資訊管理視窗,其結構示意圖如圖20-7所示:圖20-7 引入了中介者類的“客戶資訊

物件的克隆——原型模式:淺克隆,深克隆

7.4 帶附件的週報 通過引入原型模式,Sunny軟體公司OA系統支援工作週報的快速克隆,極大提高了工作週報的編寫效率,受到員工的一致好評。但有員工又發現一個問題,有些工作週報帶有附件,例如經理助理“小龍女”的週報通常附有本週專案進展報告彙總表、本週客戶反饋資

遍歷聚合物件中的元素——迭代器模式

3 完整解決方案       為了簡化AbstractObjectList類的結構,並給不同的具體資料集合類提供不同的遍歷方式,Sunny軟體公司開發人員使用迭代器模式來重構AbstractObjectList類的設計,重構之後的銷售管理系統資料遍歷結構如圖4所示:圖4銷售管

實現物件的複用——享元模式:圍棋棋子的解決方案

14.3 完整解決方案 為了節約儲存空間,提高系統性能,Sunny公司開發人員使用享元模式來設計圍棋軟體中的棋子,其基本結構如圖14-4所示: 在圖14-4中,IgoChessman充當抽象享元類,BlackIgoChessman和WhiteIgoChe

確保物件的唯一性——單例模式

3.4 餓漢式單例與懶漢式單例的討論      Sunny公司開發人員使用單例模式實現了負載均衡器的設計,但是在實際使用中出現了一個非常嚴重的問題,當負載均衡器在啟動過程中使用者再次啟動該負載均衡器時,

訪問者模式Visitor

.com stat 處理 com rac code 訪問者 難了 site 訪問者模式:表示一個作用於某個對象結構中的各元素的操作。它使你可以在不改變元素的類的前提下定義作用於這些元素的新操作。 訪問者模式適用於數據結構相對穩定的系統。它吧數據結構和作用於結構上的操作之間的

java設計模式模板模式

pro str pan style coff pub 調用 類定義 ted   抽象類中公開定義了執行它的方法的方式,子類可以按需求重寫方法實現,但調用將以抽象類中定義的方式進行,典型應用如銀行辦理業務流程、沖泡飲料流程。下面給出簡單例子,用沸水沖泡飲料,分為四步:將水煮沸

設計模式裝飾者模式Decorator

不知道 operation 總結 界面 都是 per @override stat override   裝飾者模式針對的問題是:對一個結構已經確定的類,在不改變該類的結構的情況下,動態增加一些功能。   一般來說,都是對一些已經寫好的架構增加自己的功能,或者應對多種情況,

設計模式---抽象工廠模式

ava des 模式 println 5.5 mage test 抽象工廠 urn 1、 簡介:為創建一組相關或相互依賴的對象提供一個接口,無需指定它們的具體類。抽象工廠模式通常是用於創創建一族產品,並且這族產品分不同的等級;不同的具體工廠類生產不同等級的一族產品。 2、

多線程:多線程設計模式:Master-Worker模式

fonts strong stat bre not 多線程 too () 部分 Master-Worker模式是常用的並行模式之一,它的核心思想是,系統有兩個進程協作工作:Master進程,負責接收和分配任務;Worker進程,負責處理子任務。當Worker進程將子任務處理

23種設計模式9訪問者模式

類方法 打印 interface 增加 http col visitor 設計模式的 接口 定義:封裝某些作用於某種數據結構中各元素的操作,它可以在不改變數據結構的前提下定義作用於這些元素的新的操作。 類型:行為類模式 類圖: 訪問者模式可能是行為類模式中最

設計模式 工廠模式

初始化 重要 不能 還需 new 不同 參數 裏的 作用 概述: 屬於創建型設計模式,需要生成的對象叫做產品 ,生成對象的地方叫做工廠 。 使用場景: 在任何需要生成復雜對象的地方,都可以使用工廠方法模式。 直接用new可以完成的不需要用工廠模式 下面將介紹五種工廠

GOF23設計模式訪問者模式visitor

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