外觀模式及其改進(一):外觀模式概述

Liuwei-Sunny發表於2012-07-29

      外觀模式是使用頻率最高的結構型設計模式之一,無論是在Web應用軟體或是桌面應用軟體,還是在移動應用軟體中,外觀模式都得到了廣泛的應用。

      外觀模式要求外部與一個子系統的通訊可以通過一個統一的外觀物件進行,為子系統中的一組介面提供一個一致的入口,它定義了一個高層介面,這個介面使得相關子系統更加容易使用。如果沒有外觀角色,每個客戶端可能需要和多個子系統之間進行復雜的互動,系統的耦合度將很大,如圖1(A)所示;而增加一個外觀角色之後,客戶端只需要直接與外觀角色互動,客戶端與子系統之間原有的複雜關係由外觀角色來實現,從而降低了系統的耦合度,如圖1(B)所示。在圖1(B)中,Facade表示一個外觀角色,在客戶端可以呼叫這個角色的方法,它將所有從客戶端發來的請求委派到相應的子系統去,傳遞給相應的子系統物件處理。

      GoF外觀模式類圖可簡化為圖2所示結構:

圖2 GoF外觀模式簡化類圖

【嚴格地說,外觀模式沒有一個統一的類圖,圖2也只能認為是外觀模式的一種結構示意圖。】

      在外觀模式結構圖中包含如下幾個角色:

      ● Facade(外觀角色):在客戶端可以呼叫這個角色的方法,在外觀角色中可以知道相關的(一個或者多個)子系統的功能和責任;在正常情況下,它將所有從客戶端發來的請求委派到相應的子系統去,傳遞給相應的子系統物件處理。

      ● Subsystem(子系統角色):在軟體系統中可以有一個或者多個子系統角色,每一個子系統可以不是一個單獨的類,而是一個類的集合,它實現子系統的功能;每一個子系統都可以被客戶端直接呼叫,或者被外觀角色呼叫,它處理由外觀類傳過來的請求;子系統並不知道外觀的存在,對於子系統而言,外觀角色僅僅是另外一個客戶端而已。

  

      下面通過一個簡單例項來進一步說明外觀模式及其用途:

      某系統需要提供一個檔案加密模組,可以對檔案中的資料進行加密並將加密之後的資料儲存在一個新檔案中,具體的流程包括三個部分,分別是讀取原始檔、加密、儲存加密之後的檔案,其中,讀取檔案和儲存檔案使用流來實現,加密操作通過求模運算實現。這三個操作相對獨立,為了實現程式碼的獨立重用,讓設計更符合單一職責原則,這三個操作的業務程式碼封裝在三個不同的類中。現使用外觀模式對該檔案加密模組進行設計,得到初始設計方案如圖3所示:

圖3 檔案加密模組初始設計方案結構圖

      在圖3中,EncryptFacade充當外觀類,FileReaderCipherMachineFileWriter充當子系統類。完整程式碼如下所示:

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileNotFoundException;
import java.io.IOException;

//檔案讀取類:子系統類
class FileReader {
	public String read(String fileNameSrc) {
		System.out.print("讀取檔案,獲取明文:");
		StringBuffer sb = new StringBuffer();
		try{
			FileInputStream inFS = new FileInputStream(fileNameSrc);		
			int data;
    		while((data = inFS.read())! = -1) {
    			sb = sb.append((char)data);
    		}
     		inFS.close();
     		System.out.println(sb.toString());
		}
		catch(FileNotFoundException e) {
			System.out.println("檔案不存在!");
		}
		catch(IOException e) {
			System.out.println("檔案操作錯誤!");
		}
		return sb.toString();
	}
}

//資料加密類:子系統類
class CipherMachine {
	public String encrypt(String plainText) {
		System.out.print("資料加密,將明文轉換為密文:");
		String es = "";
		for(int i = 0; i < plainText.length(); i++) {
			String c = String.valueOf(plainText.charAt(i) % 7);
			es += c;
		}
		System.out.println(es);
		return es;
	}
}

//檔案儲存類:子系統類
class FileWriter {
	public void write(String encryptStr,String fileNameDes) {
		System.out.println("儲存密文,寫入檔案。");
		try{
     		FileOutputStream outFS = new FileOutputStream(fileNameDes);
      		outFS.write(encryptStr.getBytes());
      		outFS.close();
		}	
		catch(FileNotFoundException e) {
			System.out.println("檔案不存在!");
		}
		catch(IOException e) {
			System.out.println("檔案操作錯誤!");
		}		
	}
}

//加密外觀類:外觀類
class EncryptFacade {
    //維持對其他物件的引用
	private FileReader reader;
	private CipherMachine cipher;
	private FileWriter writer;
	
	public EncryptFacade() {
		reader = new FileReader();
		cipher = new CipherMachine();
		writer = new FileWriter();
	}
	
    //呼叫其他物件的業務方法
	public void fileEncrypt(String fileNameSrc, String fileNameDes) {
		String plainStr = reader.read(fileNameSrc);
		String encryptStr = cipher.encrypt(plainStr);
		writer.write(encryptStr,fileNameDes);
	}
}

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

class Client {
	public static void main(String args[]) {
		EncryptFacade ef = new EncryptFacade();
		ef.fileEncrypt("facade/src.txt","facade/des.txt");
	}
}

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

讀取檔案,獲取明文:Hello world!

資料加密,將明文轉換為密文:233364062325

儲存密文,寫入檔案。

      在本例項中,對facade資料夾下的檔案src.txt中的資料進行加密,該檔案內容為“Hello world!”,加密之後將密文儲存到facade資料夾下的另一個檔案des.txt中,程式執行後儲存在檔案中的密文為“233364062325”。在加密類CipherMachine中,採用求模運算對明文進行加密,將明文中的每一個字元除以一個整數(本例中為7,可以由使用者設定)後取餘數作為密文。

 

      作為最常用的設計模式之一,外觀模式具有以下優點

      (1) 對客戶端遮蔽了子系統元件,減少了客戶端所需處理的物件數目並使得子系統使用起來更加容易;

      (2) 實現了子系統與客戶端之間的鬆耦合關係,這使得子系統的變化不會影響到呼叫它的客戶端,只需要調整外觀類即可;

      (3) 一個子系統的修改對其他子系統沒有任何影響,而且子系統內部變化也不會影響到外觀物件。

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

相關文章