場景:
炒股,現在是全民炒股的時代,然而全民炒股,由於大多投資者對衆多股票的聯繫太多,反而不利於股票操作,這在軟件中叫藕合性過高。
而投資的另一種方式:基金,它將投資者分散的資金集中起來,交由專業的經理人進行管理,投資於股票,債券,外匯等領域。
而基金投資的收益是持有者所有。
管理機構只收取一定比例的託管費用。
這種買基金的方式就類似於軟件開發裏面的外觀模式.
意圖:
外觀模式定義了一個將子系統的一組接口集成在一起的高層接口,以提供一個一致的界面。通過這個界面,其他系統可以方便地調用子系統中的功能,而忽略子系統內部發生的變化…
使用場合:
1、爲一個比較複雜的子系統提供一個簡單的接口。
2、將客戶程序與子系統的實現部分分離,提高子系統的獨立性和可移植性。
3、簡化子系統間的依賴關係。
外觀模式(Facede pattern)涉及到子系統的一些類。
所謂子系統,是爲提供一系列相關的特徵〔功能)而緊密關聯的一組類。
例如,一個Account類、Address類和CreditCerd類相互關聯。
成爲子系統的一部分,提供在線客戶的特徵。
在真實的應用系統中,一個子系統可能由很多類組成。
子系統的客戶爲了它們的需要,需要和子系統中的一些類進行交互。
客戶和子系統的類進行直接的交互會導致客戶端對象和子系統(Figurel)之間高度耦合。
任何的類似於對子系統中類的接口的修改,會對依賴於它的所有的客戶類造成影響。
外觀模式(Facede pattern)很適用於在上述情況;
外觀模式(Facede pattern)爲子系統提供了一個更高層次、更簡單的接口。
從而降低了子系統的複雜度和依賴。
這使得子系統更易於使用和管理。
外觀是一個能爲子系統和客戶提供簡單接口的類。
當正確的應用外觀,客戶不再直接和子系統中的類交互.而是與外觀交互。
外觀承擔與子系統中類交互的責任。
實際上,外觀是子系統與客戶的接口,這樣外觀模式降低了子系統和客戶的耦合度
從圖中我們可以看到:
外觀對象隔離了客戶和子系統對象,從而降低了藕合度。
當子系統中的類進行改變時,客戶端不會像以前一樣受到影響。
儘管客戶使用由外觀提供的簡單接口,但是當需要的時候,客戶端還是可以視外觀不存在,直接訪問子系統中的底層次的接口。
這種情況下,它們之間的依賴/藕合度和原來一樣
應用實例:
我們來建立一個應用:
1、接受客戶的詳細資料(賬戶、地址和信用卡信息)。
2、驗證輸入的信息。
3、保存輸人的信息到相應的文件中。
這個應用有三個類:Account, Address和CreditCard。每一個類都有自己的驗證和保存數據的方法。
Account類
public class Account {
String firstName;
String lastName;
final String ACCOUNT_DATA_FILE ="AccountData.txt";
public Account(String firstName,String lastName){
this.firstName = firstName;
this.lastName = lastName;
}
public String getFirstName() {
return firstName;
}
public String getLastName() {
return lastName;
}
public boolean isValid(){
/*
let's go with simpler validation
here to keep example simpler;
*/
return true;
}
public boolean save(){
/*
let's go with simpler validation
here to keep example simpler;
*/
return true;
}
}
Address 類
public class Address {
String address;
String city;
String state;
final String Address_DATA_FILE ="AddressData.txt";
public Address(String address,String city, String state){
this.address = address;
this.city = city;
this.state = state;
}
public String getAddress() {
return address;
}
public String getCity() {
return city;
}
public String getState() {
return state;
}
public boolean isValid(){
/*
let's go with simpler validation
here to keep example simpler;
*/
return true;
}
public boolean save(){
/*
let's go with simpler validation
here to keep example simpler;
*/
return true;
}
}
CreditCard 類
public class CreditCard {
String cardType;
String cardNumber;
String cardExpDate;
final String CreditCard_DATA_FILE ="CreditCardData.txt";
public CreditCard(String cardType,String cardNumber, String cardExpDate){
this.cardType = cardType;
this.cardExpDate = cardExpDate;
this.cardNumber = cardNumber;
}
public String getCardType() {
return cardType;
}
public String getCardNumber() {
return cardNumber;
}
public String getCardExpDate() {
return cardExpDate;
}
public boolean isValid(){
/*
let's go with simpler validation
here to keep example simpler;
*/
return true;
}
public boolean save(){
/*
let's go with simpler validation
here to keep example simpler;
*/
return true;
}
}
以上是子系統的內部功能類,然後我們建一個外觀CustomerFacede 類供外界訪問:
public class CustomerFacede {
private String firstName;
private String lastName;
private String address;
private String city;
private String state;
private String cardType;
private String cardNumber;
private String cardExpDate;
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
public void setAddress(String address) {
this.address = address;
}
public void setCity(String city) {
this.city = city;
}
public void setState(String state) {
this.state = state;
}
public void setCardType(String cardType) {
this.cardType = cardType;
}
public void setCardNumber(String cardNumber) {
this.cardNumber = cardNumber;
}
public void setCardExpDate(String cardExpDate) {
this.cardExpDate = cardExpDate;
}
public boolean saveCustomerData(){
Address objAdress;
Account objAccount;
CreditCard objCreditCard;
boolean validData = true;
String errorMsg = "";
objAccount = new Account(firstName,lastName);
if(!objAccount.isValid()){
validData =false;
errorMsg = "invalid firstName/lastName";
}
objAdress = new Address(address,city,state);
if(!objAdress.isValid()){
validData =false;
errorMsg = "invalid address/city/state";
}
objCreditCard = new CreditCard(cardType,cardNumber,cardExpDate);
if(!objCreditCard.isValid()){
validData =false;
errorMsg = "invalid cardType/cardNumber/cardExpDate";
}
if(!validData){
System.out.print(errorMsg);
}
if(objAccount.save() && objAdress.save() && objCreditCard.save()){
return true;
}else {
return false;
}
}
}
最後,我們寫一個測試AccountManager 類:
//通過CustomerFacede 分別對子系統的三個功能模塊進行操作,而不需要知道其內部結構.
public class AccountManager {
public static void main(String[] args) {
CustomerFacede facede = new CustomerFacede();
facede.setFirstName("summer");
facede.saveCustomerData();
facede.setAddress("China zhuzhou");
facede.saveCustomerData();
facede.setCardType("VISA");
facede.saveCustomerData();
}
}
客戶AccountManager不是直接和子系統的每一個組件交互,而是使用了由CustomerFacede對象提供的驗證和保存客戶數據的更高層次、更簡單的接口.
在新的設計中,爲了驗證和保存客戶數據,客戶需要:
1,建立或獲得外觀對象CustomFacade的一個實例。
2,傳遞數據給CustomFacade實例進行驗證和保存。
3,調用CustomFacade實例上的saveCustomerData方法。
CustomerFacede處理創建子系統中必要的對象並且調用這些對象上相應的驗證、保存客戶數據的方法這些細節間題。
客戶不再需要直接訪問任何的子系統中的對象。
注意事項:
1、在設計外觀時,不需要增加額外的功能。
2、不要從外觀方法中返回子系統中的組件給客戶。例如:有一個下面的方法:CreditCard getCteditCard0會報漏子系統的細節給客戶。應用就不能從應用外觀模式中取得最大的好處。
3、應用外觀的目的是提供一個高層次的接口。
因此,外觀方法最適合提供特定的高層次的業務服務,而不是進行底層次的單獨的業務執行。.