Java设计模式之外观模式研究.docx
《Java设计模式之外观模式研究.docx》由会员分享,可在线阅读,更多相关《Java设计模式之外观模式研究.docx(13页珍藏版)》请在冰豆网上搜索。
Java设计模式之外观模式研究
Java设计模式之外观模式研究
外观模式(Facadepattern)涉及到子系统的一些类。
所谓子系统,是为提供一系列相关的特征(功能)而紧密关联的一组类。
例如,一个Account类、Address类和CreditCard类相互关联,成为子系统的一部分,提供在线客户的特征。
在真实的应用系统中,一个子系统可能由很多类组成。
子系统的客户为了它们的需要,需要和子系统中的一些类进行交互。
客户和子系统的类进行直接的交互会导致客户端对象和子系统(Figure1)之间高度耦合。
任何的类似于对子系统中类的接口的修改,会对依赖于它的所有的客户类造成影响。
Figure1:
ClientInteractionwithSubsystemClassesbeforeApplyingtheFacadePattern
外观模式(Facadepattern)很适用于在上述情况。
外观模式(Facadepattern)为子系统提供了一个更高层次、更简单的接口,从而降低了子系统的复杂度和依赖。
这使得子系统更易于使用和管理。
外观是一个能为子系统和客户提供简单接口的类。
当正确的应用外观,客户不再直接和子系统中的类交互,而是与外观交互。
外观承担与子系统中类交互的责任。
实际上,外观是子系统与客户的接口,这样外观模式降低了子系统和客户的耦合度(Figure2).
Figure2:
ClientInteractionwithSubsystemClassesafterApplyingtheFacadePattern
从Figure2中我们可以看到:
外观对象隔离了客户和子系统对象,从而降低了耦合度。
当子系统中的类进行改变时,客户端不会像以前一样受到影响。
尽管客户使用由外观提供的简单接口,但是当需要的时候,客户端还是可以视外观不存在,直接访问子系统中的底层次的接口。
这种情况下,它们之间的依赖/耦合度和原来一样。
例子:
让我们建立一个应用:
(1)接受客户的详细资料(账户、地址和信用卡信息)
(2)验证输入的信息
(3)保存输入的信息到相应的文件中。
这个应用有三个类:
Account、Address和CreditCard。
每一个类都有自己的验证和保存数据的方法。
Listing1:
AccountClass
publicclassAccount{
StringfirstName;
StringlastName;
finalStringACCOUNT_DATA_FILE="AccountData.txt";
publicAccount(Stringfname,Stringlname){
firstName=fname;
lastName=lname;
}
publicbooleanisValid(){
/*
Let'sgowithsimplervalidation
heretokeeptheexamplesimpler.
*/
…
…
}
publicbooleansave(){
FileUtilfutil=newFileUtil();
StringdataLine=getLastName()+”,"+getFirstName();
returnfutil.writeToFile(ACCOUNT_DATA_FILE,dataLine,true,true);
}
publicStringgetFirstName(){
returnfirstName;
}
publicStringgetLastName(){
returnlastName;
}
}
Listing2:
AddressClass
publicclassAddress{
Stringaddress;
Stringcity;
Stringstate;
finalStringADDRESS_DATA_FILE="Address.txt";
publicAddress(Stringadd,Stringcty,Stringst){
address=add;
city=cty;
state=st;
}
publicbooleanisValid(){
/*
Theaddressvalidationalgorithm
couldbecomplexinreal-world
applications.
Let'sgowithsimplervalidation
heretokeeptheexamplesimpler.
*/
if(getState().trim().length()<2)
returnfalse;
returntrue;
}
publicbooleansave(){
FileUtilfutil=newFileUtil();
StringdataLine=getAddress()+”,"+getCity()+”,"+getState();
returnfutil.writeToFile(ADDRESS_DATA_FILE,dataLine,true,true);
}
publicStringgetAddress(){
returnaddress;
}
publicStringgetCity(){
returncity;
}
publicStringgetState(){
returnstate;
}
}
Listing3:
CreditCardClass
publicclassCreditCard{
StringcardType;
StringcardNumber;
StringcardExpDate;
finalStringCC_DATA_FILE="CC.txt";
publicCreditCard(StringccType,StringccNumber,
StringccExpDate){
cardType=ccType;
cardNumber=ccNumber;
cardExpDate=ccExpDate;
}
publicbooleanisValid(){
/*
Let'sgowithsimplervalidation
heretokeeptheexamplesimpler.
*/
if(getCardType().equals(AccountManager.VISA)){
return(getCardNumber().trim().length()==16);
}
if(getCardType().equals(AccountManager.DISCOVER)){
return(getCardNumber().trim().length()==15);
}
if(getCardType().equals(AccountManager.MASTER)){
return(getCardNumber().trim().length()==16);
}
returnfalse;
}
publicbooleansave(){
FileUtilfutil=newFileUtil();
StringdataLine=getCardType()+,”"+getCardNumber()+”,"+getCardExpDate();
returnfutil.writeToFile(CC_DATA_FILE,dataLine,true,true);
}
publicStringgetCardType(){
returncardType;
}
publicStringgetCardNumber(){
returncardNumber;
}
publicStringgetCardExpDate(){
returncardExpDate;
}
}
Figure3:
SubsystemClassestoProvidetheNecessaryFunctionalitytoValidateandSavetheCustomerData
让我们建立一个客户AccountManager,它提供用户输入数据的用户界面。
Listing4:
ClientAccountManagerClass
publicclassAccountManagerextendsJFrame{
publicstaticfinalStringnewline="\n";
publicstaticfinalStringVALIDATE_SAVE="Validate&Save";
…
…
publicAccountManager(){
super("FacadePattern-Example");
cmbCardType=newJComboBox();
cmbCardType.addItem(AccountManager.VISA);
cmbCardType.addItem(AccountManager.MASTER);
cmbCardType.addItem(AccountManager.DISCOVER);
…
…
//Createbuttons
JButtonvalidateSaveButton=newJButton(AccountManager.VALIDATE_SAVE);
…
…
}
publicStringgetFirstName(){
returntxtFirstName.getText();
}
…
…
}//EndofclassAccountManager
当客户AccountManage运行的时候,展示的用户接口如下:
Figure4:
UserInterfacetoEntertheCustomerData
为了验证和保存输入的数据,客户AccountManager需要:
(1)建立Account、Address和CreditCard对象。
(2)用这些对象验证输入的数据
(3)用这些对象保存输入的数据。
下面是对象间的交互顺序图:
Figure5:
HowaClientWouldNormallyInteract(Directly)withSubsystemClassestoValidateandSavetheCustomerData
在这个例子中应用外观模式是一个很好的设计,它可以降低客户和子系统组件(Address、Account和CreditCard)之间的耦合度。
应用外观模式,让我们定义一个外观类CustomerFacade(Figure6andListing5)。
它为由客户数据处理类(Address、Account和CreditCard)所组成的子系统提供一个高层次的、简单的接口。
CustomerFacade
address:
String
city:
String
state:
String
cardType:
String
cardNumber:
String
cardExpDate:
String
fname:
String
lname:
String
setAddress(inAddress:
String)
setCity(inCity:
String)
setState(inState:
String)
setCardType(inCardType:
String)
setCardNumber(inCardNumber:
String)
setCardExpDate(inCardExpDate:
String)
setFName(inFName:
String)
setLName(inLName:
String)
saveCustomerData()
Figure6:
FacadeClasstoBeUsedbytheClientintheRevisedDesign
Listing5:
CustomerFacadeClass
publicclassCustomerFacade{
privateStringaddress;
privateStringcity;
privateStringstate;
privateStringcardType;
privateStringcardNumber;
privateStringcardExpDate;
privateStringfname;
privateStringlname;
publicvoidsetAddress(StringinAddress){
address=inAddress;
}
publicvoidsetCity(StringinCity){
city=inCity;
}
publicvoidsetState(StringinState){
state=inState;
}
publicvoidsetFName(StringinFName){
fname=inFName;
}
publicvoidsetLName(StringinLName){
lname=inLName;
}
publicvoidsetCardType(StringinCardType){
cardType=inCardType;
}
publicvoidsetCardNumber(StringinCardNumber){
cardNumber=inCardNumber;
}
publicvoidsetCardExpDate(StringinCardExpDate){
cardExpDate=inCardExpDate;
}
publicbooleansaveCustomerData(){
AddressobjAddress;
AccountobjAccount;
CreditCardobjCreditCard;
/*
clientistransparentfromthefollowing
setofsubsystemrelatedoperations.
*/
booleanvalidData=true;
StringerrorMessage="";
objAccount=newAccount(fname,lname);
if(objAccount.isValid()==false){
validData=false;
errorMessage="InvalidFirstName/LastName";
}
objAddress=newAddress(address,city,state);
if(objAddress.isValid()==false){
validData=false;
errorMessage="InvalidAddress/City/State";
}
objCreditCard=newCreditCard(cardType,cardNumber,cardExpDate);
if(objCreditCard.isValid()==false){
validData=false;
errorMessage="InvalidCreditCardInfo";
}
if(!
validData){
System.out.println(errorMessage);
returnfalse;
}
if(objAddress.save()&&objAccount.save()&&objCreditCard.save()){
returntrue;
}else{
returnfalse;
}
}
}
CustomerFacade类以saveCustomData方法的形式提供了业务层次上的服务。
客户AccountManager不是直接和子系统的每一个组件交互,而是使用了由CustomFacade对象提供的验证和保存客户数据的更高层次、更简单的接口(Figure7).
Figure7:
ClassAssociationwiththeFa?
adeClassinPlace。
在新的设计中,为了验证和保存客户数据,客户需要:
(1)建立或获得外观对象CustomFacade的一个实例。
(2)传递数据给CustomFacade实例进行验证和保存。
(3)调用CustomFacade实例上的saveCustomData方法。
CustomFacade处理创建子系统中必要的对象并且调用这些对象上相应的验证、保存客户数据的方法这些细节问题。
客户不再需要直接访问任何的子系统中的对象。
Figure8展示了新的设计的消息流图:
Figure22.8:
IntheRevisedDesign,ClientsInteractwiththeFa?
adeInstancetoInterfacewiththeSubsystem
重要提示:
下面是应用外观模式的注意事项:
(1)在设计外观时,不需要增加额外的功能。
(2)不要从外观方法中返回子系统中的组件给客户。
例如:
有一个下面的方法:
CreditCardgetCreditCard()
会暴露子系统的细节给客户。
应用就不能从应用外观模式中取得最大的好处。
(3)应用外观的目的是提供一个高层次的接口。
因此,外观方法最适合提供特定的高层次的业务服务,而不是进行底层次的单独的业务执行。