1. 程式人生 > >協調多個物件之間的互動——中介者模式(四)

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

20.4 中介者與同事類的擴充套件

       Sunny軟體公司CRM系統的客戶對“客戶資訊管理視窗”提出了一個修改意見:要求在視窗的下端能夠及時顯示當前系統中客戶資訊的總數。修改之後的介面如圖20-9所示:

20-9 修改之後的“客戶資訊管理視窗”介面圖

從圖20-9中我們不難發現,可以通過增加一個文字標籤(Label)來顯示客戶資訊總數,而且當用戶點選“增加”按鈕或者“刪除”按鈕時,將改變文字標籤的內容。

      由於使用了中介者模式,在原有系統中增加新的元件(即新的同事類)將變得很容易,我們至少有如下兩種解決方案:

【解決方案一】增加一個介面元件類Label,修改原有的具體中介者類ConcreteMediator

,增加一個對Label物件的引用,然後修改componentChanged()方法中其他相關元件物件的業務處理程式碼,原有元件類無須任何修改,客戶端程式碼也需針對新增元件Label進行適當修改。

【解決方案二】與方案一相同,首先增加一個Label類,但不修改原有具體中介者類ConcreteMediator的程式碼,而是增加一個ConcreteMediator的子類SubConcreteMediator來實現對Label物件的引用,然後在新增的中介者類SubConcreteMediator中通過覆蓋componentChanged()方法來實現所有元件(包括新增Label元件)之間的互動,同樣,原有元件類無須做任何修改,客戶端程式碼需少許修改。

      引入Label之後“客戶資訊管理視窗”類結構示意圖如圖20-10所示:

20-10 增加Label元件類後的“客戶資訊管理視窗”結構示意圖

由於【解決方案二】無須修改ConcreteMediator類,更符合“開閉原則”,因此我們選擇該解決方案來對新增Label類進行處理,對應的完整類圖如圖20-11所示:

20-11 修改之後的“客戶資訊管理視窗”結構圖

      在圖20-11中,新增了具體同事類Label和具體中介者類SubConcreteMediator,程式碼如下所示:

//文字標籤類:具體同事類
class Label extends Component {
	public void update() {
		System.out.println("文字標籤內容改變,客戶資訊總數加1。");
	}
}

//新增具體中介者類
class SubConcreteMediator extends ConcreteMediator {
	//增加對Label物件的引用
	public Label label;
	
	public void componentChanged(Component c) {
	    //單擊按鈕
if(c == addButton) {
			System.out.println("--單擊增加按鈕--");
			list.update();
			cb.update();
			userNameTextBox.update();
			label.update(); //文字標籤更新
		}
        //從列表框選擇客戶
		else if(c == list) {
			System.out.println("--從列表框選擇客戶--");
			cb.select();
			userNameTextBox.setText();
		}
        //從組合框選擇客戶
		else if(c == cb) {
			System.out.println("--從組合框選擇客戶--");
			cb.select();
			userNameTextBox.setText();
		}
	}
}

       修改客戶端測試程式碼:

class Client {
	public static void main(String args[]) {
        //用新增具體中介者定義中介者物件
		SubConcreteMediator mediator;
		mediator = new SubConcreteMediator();
		
		Button addBT = new Button();
		List list = new List();
	    ComboBox cb = new ComboBox();
	    TextBox userNameTB = new TextBox();
	    Label label = new Label();

		addBT.setMediator(mediator);
		list.setMediator(mediator);
		cb.setMediator(mediator);
		userNameTB.setMediator(mediator);
		label.setMediator(mediator);
		
		mediator.addButton = addBT;
		mediator.list = list;
		mediator.cb = cb;
		mediator.userNameTextBox = userNameTB;
		mediator.label = label;
			
		addBT.changed();
		System.out.println("-----------------------------");
		list.changed();
	}
}

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

--單擊增加按鈕--

列表框增加一項:張無忌。

組合框增加一項:張無忌。

客戶資訊增加成功後文本框清空。

文字標籤內容改變,客戶資訊總數加1

-----------------------------

--從列表框選擇客戶--

組合框選中項:小龍女。

文字框顯示:小龍女。

由於在本例項中不同的元件類(即不同的同事類)所擁有的方法並不完全相同,因此中介者類沒有針對抽象同事類程式設計,導致在具體中介者類中需要維持對具體同事類的引用,客戶端程式碼無法完全透明地對待所有同事類和中介者類。在某些情況下,如果設計得當,可以在客戶端透明地對同事類和中介者類程式設計,這樣系統將具有更好的靈活性和可擴充套件性。

疑問

思考

如果不使用中介者模式,按照圖20-3所示設計方案,增加新元件時原有系統該如何修改?

在中介者模式的實際使用過程中,如果需要引入新的具體同事類,只需要繼承抽象同事類並實現其中的方法即可,由於具體同事類之間並無直接的引用關係,因此原有所有同事類無須進行任何修改,它們與新增同事物件之間的互動可以通過修改或者增加具體中介者類來實現如果需要在原有系統中增加新的具體中介者類,只需要繼承抽象中介者類(或已有的具體中介者類)並覆蓋其中定義的方法即可,在新的具體中介者中可以通過不同的方式來處理物件之間的互動,也可以增加對新增同事的引用和呼叫。在客戶端中只需要修改少許程式碼(如果引入配置檔案的話有時可以不修改任何程式碼)就可以實現中介者的更換。