樹形結構的處理——組合模式(四)

Liuwei-Sunny發表於2012-09-07

11.4  透明組合模式與安全組合模式

      通過引入組合模式,Sunny公司設計的防毒軟體具有良好的可擴充套件性,在增加新的檔案型別時,無須修改現有類庫程式碼,只需增加一個新的檔案類作為AbstractFile類的子類即可,但是由於在AbstractFile中宣告瞭大量用於管理和訪問成員構件的方法,例如add()remove()等方法,我們不得不在新增的檔案類中實現這些方法,提供對應的錯誤提示和異常處理。為了簡化程式碼,我們有以下兩個解決方案:

      解決方案一:將葉子構件的add()remove()等方法的實現程式碼移至AbstractFile類中,由AbstractFile提供統一的預設實現,程式碼如下所示:

//提供預設實現的抽象構件類
abstract class AbstractFile {
	public void add(AbstractFile file) {
		System.out.println("對不起,不支援該方法!");
	}
	
	public void remove(AbstractFile file) {
		System.out.println("對不起,不支援該方法!");
	}
	
	public AbstractFile getChild(int i) {
		System.out.println("對不起,不支援該方法!");
		return null;
	}
	
	public abstract void killVirus();
}

      如果客戶端程式碼針對抽象類AbstractFile程式設計,在呼叫檔案物件的這些方法時將出現錯誤提示。如果不希望出現任何錯誤提示,我們可以在客戶端定義檔案物件時不使用抽象層,而直接使用具體葉子構件本身,客戶端程式碼片段如下所示:

class Client {
	public static void main(String args[]) {
        //不能透明處理葉子構件
		ImageFile file1,file2;
		TextFile file3,file4;
		VideoFile file5;
		AbstractFile folder1,folder2,folder3,folder4;
        //其他程式碼省略
      }
}

      這樣就產生了一種不透明的使用方式,即在客戶端不能全部針對抽象構件類程式設計,需要使用具體葉子構件型別來定義葉子物件。

      解決方案二:除此之外,還有一種解決方法是在抽象構件AbstractFile中不宣告任何用於訪問和管理成員構件的方法,程式碼如下所示:

abstract class AbstractFile {
	public abstract void killVirus();
}

      此時,由於在AbstractFile中沒有宣告add()、remove()等訪問和管理成員的方法,其葉子構件子類無須提供實現;而且無論客戶端如何定義葉子構件物件都無法呼叫到這些方法,不需要做任何錯誤和異常處理,容器構件再根據需要增加訪問和管理成員的方法,但這時候也存在一個問題:客戶端不得不使用容器類本身來宣告容器構件物件,否則無法訪問其中新增的add()、remove()等方法,如果客戶端一致性地對待葉子和容器,將會導致容器構件的新增對客戶端不可見,客戶端程式碼對於容器構件無法再使用抽象構件來定義,客戶端程式碼片段如下所示:

class Client {
	public static void main(String args[]) {
		
		AbstractFile file1,file2,file3,file4,file5;
		Folder folder1,folder2,folder3,folder4; //不能透明處理容器構件
		//其他程式碼省略
	}
}

      在使用組合模式時,根據抽象構件類的定義形式,我們可將組合模式分為透明組合模式和安全組合模式兩種形式:

      (1) 透明組合模式

      透明組合模式中,抽象構件Component中宣告瞭所有用於管理成員物件的方法,包括add()remove()以及getChild()等方法,這樣做的好處是確保所有的構件類都有相同的介面。在客戶端看來,葉子物件與容器物件所提供的方法是一致的,客戶端可以相同地對待所有的物件。透明組合模式也是組合模式的標準形式,雖然上面的解決方案一在客戶端可以有不透明的實現方法,但是由於在抽象構件中包含add()remove()等方法,因此它還是透明組合模式,透明組合模式的完整結構如圖11-6所示:

11-6  透明組合模式結構圖

      透明組合模式的缺點是不夠安全,因為葉子物件和容器物件在本質上是有區別的。葉子物件不可能有下一個層次的物件,即不可能包含成員物件,因此為其提供add()remove()以及getChild()等方法是沒有意義的,這在編譯階段不會出錯,但在執行階段如果呼叫這些方法可能會出錯(如果沒有提供相應的錯誤處理程式碼)。

      (2) 安全組合模式

      安全組合模式中,在抽象構件Component中沒有宣告任何用於管理成員物件的方法,而是在Composite類中宣告並實現這些方法。這種做法是安全的,因為根本不向葉子物件提供這些管理成員物件的方法,對於葉子物件,客戶端不可能呼叫到這些方法,這就是解決方案二所採用的實現方式。安全組合模式的結構如圖11-7所示:

11-7  安全組合模式結構圖

       安全組合模式的缺點是不夠透明,因為葉子構件和容器構件具有不同的方法,且容器構件中那些用於管理成員物件的方法沒有在抽象構件類中定義,因此客戶端不能完全針對抽象程式設計,必須有區別地對待葉子構件和容器構件。在實際應用中,安全組合模式的使用頻率也非常高,在Java AWT中使用的組合模式就是安全組合模式。

【作者:劉偉 http://blog.csdn.net/lovelion

相關文章