Java设计模式之外观模式研究

<script type="text/javascript"> var arrBaiduCproConfig=new Array(); arrBaiduCproConfig['uid'] = 50987; arrBaiduCproConfig['n'] = 'lu333cpr'; arrBaiduCproConfig['tm'] = 26; arrBaiduCproConfig['cm'] = 0; arrBaiduCproConfig['um'] = 0; arrBaiduCproConfig['rad'] = 1; arrBaiduCproConfig['w'] = 598; arrBaiduCproConfig['h'] = 90; arrBaiduCproConfig['bd'] = '#FFFFFF'; arrBaiduCproConfig['bg'] = '#FFFFFF'; arrBaiduCproConfig['tt'] = '#555555'; arrBaiduCproConfig['ct'] = '#333333'; arrBaiduCproConfig['url'] = '#666666'; arrBaiduCproConfig['bdl'] = '#FFFFFF'; arrBaiduCproConfig['wn'] = 3; arrBaiduCproConfig['hn'] = 3; arrBaiduCproConfig['ta'] = 'left'; arrBaiduCproConfig['tl'] = 'top'; arrBaiduCproConfig['bu'] = 1; </script><script src="http://cpro.baidu.com/cpro/ui/ui.js" type="text/javascript"> </script><script type="text/javascript"> </script><script type="text/javascript"> var ad_dispnews_content_type = 1; var ad_dispnews_news_class = 11; var ad_dispnews_sec_class = 1103; var ad_dispnews_secname = 'Java教程'; </script><script src="http://www.gzu521.com/recommend/ad_dispnews_content.js" type="text/javascript"> </script> 外观模式(facade pattern)涉及到子系统的一些类。所谓子系统,是为提供一系列相关的特征(功能)而紧密关联的一组类。例如,一个account类、address类和creditcard类相互关联,成为子系统的一部分,提供在线客户的特征。

  在真实的应用系统中,一个子系统可能由很多类组成。子系统的客户为了它们的需要,需要和子系统中的一些类进行交互。客户和子系统的类进行直接的交互会导致客户端对象和子系统(figure1)之间高度耦合。任何的类似于对子系统中类的接口的修改,会对依赖于它的所有的客户类造成影响。

 

 

<script language="JavaScript" src="http://www.gzu521.com/JS/Std_StranJF.Js" type="text/javascript"> </script><script language="JavaScript" src="http://www.gzu521.com/recommend/float1.js" type="text/javascript"> </script>  

 

   
figure1: client interaction with subsystem classes before applying the facade pattern


  外观模式(facade pattern)很适用于在上述情况。外观模式(facade pattern)为子系统提供了一个更高层次、更简单的接口,从而降低了子系统的复杂度和依赖。这使得子系统更易于使用和管理。

  外观是一个能为子系统和客户提供简单接口的类。当正确的应用外观,客户不再直接和子系统中的类交互,而是与外观交互。外观承担与子系统中类交互的责任。实际上,外观是子系统与客户的接口,这样外观模式降低了子系统和客户的耦合度(figure2).

   
figure2: client interaction with subsystem classes after applying the facade pattern


  从figure2中我们可以看到:外观对象隔离了客户和子系统对象,从而降低了耦合度。当子系统中的类进行改变时,客户端不会像以前一样受到影响。

  尽管客户使用由外观提供的简单接口,但是当需要的时候,客户端还是可以视外观不存在,直接访问子系统中的底层次的接口。这种情况下,它们之间的依赖/耦合度和原来一样。

  例子:

  让我们建立一个应用:

  (1) 接受客户的详细资料(账户、地址和信用卡信息)

  (2) 验证输入的信息

  (3) 保存输入的信息到相应的文件中。

  这个应用有三个类:accountaddresscreditcard。每一个类都有自己的验证和保存数据的方法。

  listing1: accountclass

public class account {
 string firstname;
 
string lastname;
 
final string account_data_file = "accountdata.txt";
 
public account(string fname, string lname) {
  
firstname = fname;
  
lastname = lname;
 
}
 
public boolean isvalid() {
  
/*
  
let's go with simpler validation
  
here to keep the example simpler.
  
*/
  …

  …

 
}
 
public boolean save() {
  
fileutil futil = new fileutil();
  string dataline = getlastname() +
," + getfirstname();
  
return futil.writetofile(account_data_file, dataline,true, true);
 
}
 
public string getfirstname() {
  
return firstname;
 
}
 
public string getlastname() {
  
return lastname;
 
}
}


  listing2: address class

public class address {
 string address;
 
string city;
 
string state;
 
final string address_data_file = "address.txt";
 
public address(string add, string cty, string st) {
  
address = add;
  
city = cty;
  
state = st;
 
}
 
public boolean isvalid() {
  
/*
  
the address validation algorithm
  
could be complex in real-world
  
applications.
  
let's go with simpler validation
  
here to keep the example simpler.
  
*/
  
if (getstate().trim().length() < 2)
   
return false;
  
return true;
 
}
 
public boolean save() {
  
fileutil futil = new fileutil();
  string dataline = getaddress() + ," + getcity() +
," + getstate();
  
return futil.writetofile(address_data_file, dataline,true, true);
 
}
 
public string getaddress() {
  
return address;
 
}
 
public string getcity() {
  
return city;
 
}
 
public string getstate() {
  
return state;
 
}
}


  listing3: creditcard class

public class creditcard {
 string cardtype;
 
string cardnumber;
 
string cardexpdate;
 
final string cc_data_file = "cc.txt";
 
public creditcard(string cctype, string ccnumber,
 
string ccexpdate) {
  
cardtype = cctype;
  
cardnumber = ccnumber;
  
cardexpdate = ccexpdate;
 
}
 
public boolean isvalid() {
  
/*
  
let's go with simpler validation
  
here to keep the example simpler.
  
*/
  
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);
  
}
  
return false;
 
}
 
public boolean save() {
  
fileutil futil = new fileutil();
  string dataline = getcardtype() + ," + getcardnumber() +
," + getcardexpdate();
  
return futil.writetofile(cc_data_file, dataline, true, true);
 
}
 
public string getcardtype() {
  
return cardtype;
 
}
 
public string getcardnumber() {
  
return cardnumber;
 
}
 
public string getcardexpdate() {
  
return cardexpdate;
 
}
}

 

 

<script type="text/javascript"> var arrBaiduCproConfig=new Array(); arrBaiduCproConfig['uid'] = 50987; arrBaiduCproConfig['n'] = 'lu333cpr'; arrBaiduCproConfig['tm'] = 26; arrBaiduCproConfig['cm'] = 0; arrBaiduCproConfig['um'] = 0; arrBaiduCproConfig['rad'] = 1; arrBaiduCproConfig['w'] = 598; arrBaiduCproConfig['h'] = 90; arrBaiduCproConfig['bd'] = '#FFFFFF'; arrBaiduCproConfig['bg'] = '#FFFFFF'; arrBaiduCproConfig['tt'] = '#555555'; arrBaiduCproConfig['ct'] = '#333333'; arrBaiduCproConfig['url'] = '#666666'; arrBaiduCproConfig['bdl'] = '#FFFFFF'; arrBaiduCproConfig['wn'] = 3; arrBaiduCproConfig['hn'] = 3; arrBaiduCproConfig['ta'] = 'left'; arrBaiduCproConfig['tl'] = 'top'; arrBaiduCproConfig['bu'] = 1; </script><script src="http://cpro.baidu.com/cpro/ui/ui.js" type="text/javascript"> </script><script type="text/javascript"> </script><script type="text/javascript"> var ad_dispnews_content_type = 1; var ad_dispnews_news_class = 11; var ad_dispnews_sec_class = 1103; var ad_dispnews_secname = 'Java教程'; </script><script src="http://www.gzu521.com/recommend/ad_dispnews_content.js" type="text/javascript"> </script>     
figure3: subsystem classes to provide the necessary functionality to validate and save the customer data

 让我们建立一个客户accountmanager,它提供用户输入数据的用户界面。

  listing4: client accountmanager class

public class accountmanager extends jframe {
 public static final string newline = "/n";
 
public static final string validate_save = "validate & save";
 …

 …

 
public accountmanager() {
  
super(" facade pattern - example ");
  
cmbcardtype = new jcombobox();
  
cmbcardtype.additem(accountmanager.visa);
  
cmbcardtype.additem(accountmanager.master);
  
cmbcardtype.additem(accountmanager.discover);
  …

  …

  
//create buttons
  
jbutton validatesavebutton = new jbutton(accountmanager.validate_save);
  …

  …

 
}
 
public string getfirstname() {
  
return txtfirstname.gettext();
 
}
 …

 …

}//end of class accountmanager


  当客户accountmanage运行的时候,展示的用户接口如下:

<script language="JavaScript" src="http://www.gzu521.com/JS/Std_StranJF.Js" type="text/javascript"> </script><script language="JavaScript" src="http://www.gzu521.com/recommend/float1.js" type="text/javascript"> </script>  

 

<script type="text/javascript"> var arrBaiduCproConfig=new Array(); arrBaiduCproConfig['uid'] = 50987; arrBaiduCproConfig['n'] = 'lu333cpr'; arrBaiduCproConfig['tm'] = 26; arrBaiduCproConfig['cm'] = 0; arrBaiduCproConfig['um'] = 0; arrBaiduCproConfig['rad'] = 1; arrBaiduCproConfig['w'] = 598; arrBaiduCproConfig['h'] = 90; arrBaiduCproConfig['bd'] = '#FFFFFF'; arrBaiduCproConfig['bg'] = '#FFFFFF'; arrBaiduCproConfig['tt'] = '#555555'; arrBaiduCproConfig['ct'] = '#333333'; arrBaiduCproConfig['url'] = '#666666'; arrBaiduCproConfig['bdl'] = '#FFFFFF'; arrBaiduCproConfig['wn'] = 3; arrBaiduCproConfig['hn'] = 3; arrBaiduCproConfig['ta'] = 'left'; arrBaiduCproConfig['tl'] = 'top'; arrBaiduCproConfig['bu'] = 1; </script><script src="http://cpro.baidu.com/cpro/ui/ui.js" type="text/javascript"> </script><script type="text/javascript"> </script><script type="text/javascript"> var ad_dispnews_content_type = 1; var ad_dispnews_news_class = 11; var ad_dispnews_sec_class = 1103; var ad_dispnews_secname = 'Java教程'; </script><script src="http://www.gzu521.com/recommend/ad_dispnews_content.js" type="text/javascript"> </script>   
figure4: user interface to enter the customer data


  为了验证和保存输入的数据,客户accountmanager需要:

  (1) 建立accountaddresscreditcard对象。

  (2) 用这些对象验证输入的数据

  (3) 用这些对象保存输入的数据。

  下面是对象间的交互顺序图:

 
figure5: how a client would normally interact (directly) with subsystem classes to validate and save the customer data


  在这个例子中应用外观模式是一个很好的设计,它可以降低客户和子系统组件(addressaccountcreditcard)之间的耦合度。应用外观模式,让我们定义一个外观类customerfacade (figure6 and listing5)。它为由客户数据处理类(addressaccountcreditcard)所组成的子系统提供一个高层次的、简单的接口。

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: facade class to be used by the client in the revised design


  listing5: customerfacade class

public class customerfacade {
 private string address;
 private string city;
 private string state;
 private string cardtype;
 private string cardnumber;
 private string cardexpdate;
 private string fname;
 private string lname;
 public void setaddress(string inaddress) {
  address = inaddress;
 }
 public void setcity(string incity) {
  city = incity;
 }
 public void setstate(string instate) {
  state = instate;
 }
 public void setfname(string infname) {
  fname = infname;
 }
 public void setlname(string inlname) {
  lname = inlname;
 }
 public void setcardtype(string incardtype) {
  cardtype = incardtype;
 }
 public void setcardnumber(string incardnumber) {
  cardnumber = incardnumber;
 }
 public void setcardexpdate(string incardexpdate) {
  cardexpdate = incardexpdate;
 }
 public boolean savecustomerdata() {
  address objaddress;
  account objaccount;
  creditcard objcreditcard;
  /*
   client is transparent from the following
   set of subsystem related operations.
  */
  boolean validdata = true;
  string errormessage = "";
  objaccount = new account(fname, lname);
  if (objaccount.isvalid() == false) {
   validdata = false;
   errormessage = "invalid firstname/lastname";
  }
  objaddress = new address(address, city, state);
  if (objaddress.isvalid() == false) {
   validdata = false;
   errormessage = "invalid address/city/state";
  }
  objcreditcard = new creditcard(cardtype, cardnumber, cardexpdate);
  if (objcreditcard.isvalid() == false) {
   validdata = false;
   errormessage = "invalid creditcard info";
  }
  if (!validdata) {
   system.out.println(errormessage);
   return false;
  }
  if (objaddress.save() && objaccount.save() && objcreditcard.save()) {
   return true;
  } else {
   return false;
  }
 }
}


  customerfacade类以savecustomdata方法的形式提供了业务层次上的服务。客户accountmanager不是直接和子系统的每一个组件交互,而是使用了由customfacade对象提供的验证和保存客户数据的更高层次、更简单的接口(figure7).

<script language="JavaScript" src="http://www.gzu521.com/recommend/ad_dispnews_content_bottom.js" type="text/javascript"> </script><script language="JavaScript" src="http://www.gzu521.com/js/wangzhai.js" type="text/javascript"> </script>  

<script type="text/javascript"> var arrBaiduCproConfig=new Array(); arrBaiduCproConfig['uid'] = 50987; arrBaiduCproConfig['n'] = 'lu333cpr'; arrBaiduCproConfig['tm'] = 26; arrBaiduCproConfig['cm'] = 0; arrBaiduCproConfig['um'] = 0; arrBaiduCproConfig['rad'] = 1; arrBaiduCproConfig['w'] = 598; arrBaiduCproConfig['h'] = 90; arrBaiduCproConfig['bd'] = '#FFFFFF'; arrBaiduCproConfig['bg'] = '#FFFFFF'; arrBaiduCproConfig['tt'] = '#555555'; arrBaiduCproConfig['ct'] = '#333333'; arrBaiduCproConfig['url'] = '#666666'; arrBaiduCproConfig['bdl'] = '#FFFFFF'; arrBaiduCproConfig['wn'] = 3; arrBaiduCproConfig['hn'] = 3; arrBaiduCproConfig['ta'] = 'left'; arrBaiduCproConfig['tl'] = 'top'; arrBaiduCproConfig['bu'] = 1; </script><script src="http://cpro.baidu.com/cpro/ui/ui.js" type="text/javascript"> </script><script type="text/javascript"> </script><script type="text/javascript"> var ad_dispnews_content_type = 1; var ad_dispnews_news_class = 11; var ad_dispnews_sec_class = 1103; var ad_dispnews_secname = 'Java教程'; </script><script src="http://www.gzu521.com/recommend/ad_dispnews_content.js" type="text/javascript"> </script>  
figure7: class association with the fa?ade class in place


  在新的设计中,为了验证和保存客户数据,客户需要:

  (1) 建立或获得外观对象customfacade的一个实例。

  (2) 传递数据给customfacade实例进行验证和保存。

  (3) 调用customfacade实例上的savecustomdata方法。

  customfacade处理创建子系统中必要的对象并且调用这些对象上相应的验证、保存客户数据的方法这些细节问题。客户不再需要直接访问任何的子系统中的对象。

  figure8展示了新的设计的消息流图:

 
figure 22.8: in the revised design, clients interact with the fa?ade instance to interface with the subsystem


  重要提示

  下面是应用外观模式的注意事项:

  (1) 在设计外观时,不需要增加额外的功能。

  (2) 不要从外观方法中返回子系统中的组件给客户。例如:有一个下面的方法:

  creditcard getcreditcard()

  会报漏子系统的细节给客户。应用就不能从应用外观模式中取得最大的好处。

  (3)应用外观的目的是提供一个高层次的接口。因此,外观方法最适合提供特定的高层次的业务服务,而不是进行底层次的单独的业务执行。>

<script src="http://www.gzu521.com/recommend/google468.js" type="text/javascript"> </script>  

 

<script language="JavaScript" src="http://www.gzu521.com/JS/Std_StranJF.Js" type="text/javascript"> </script><script language="JavaScript" src="http://www.gzu521.com/recommend/float1.js" type="text/javascript"> </script>  

 

<script language="JavaScript" src="http://www.gzu521.com/JS/Std_StranJF.Js" type="text/javascript"> </script><script language="JavaScript" src="http://www.gzu521.com/recommend/float1.js" type="text/javascript"> </script>  

 

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值