| |
描述: 外观模式(fa?ade pattern)涉及到子系统的一些类。所谓子系统,是为提供一系列相关的特征(功能)而紧密关联的一组类。例如,一个account类、address类和creditcard类相互关联,成为子系统的一部分,提供在线客户的特征。 在真实的应用系统中,一个子系统可能由很多类组成。子系统的客户为了它们的需要,需要和子系统中的一些类进行交互。客户和子系统的类进行直接的交互会导致客户端对象和子系统(figure 22.1)之间高度耦合。任何的类似于对子系统中类的接口的修改,会对依赖于它的所有的客户类造成影响。  figure 22.1: client interaction with subsystem classes before applying the fa?ade pattern 外观模式(fa?ade pattern)很适用于在上述情况。外观模式(fa?ade pattern)为子系统提供了一个更高层次、更简单的接口,从而降低了子系统的复杂度和依赖。这使得子系统更易于使用和管理。 外观是一个能为子系统和客户提供简单接口的类。当正确的应用外观,客户不再直接和子系统中的类交互,而是与外观交互。外观承担与子系统中类交互的责任。实际上,外观是子系统与客户的接口,这样外观模式降低了子系统和客户的耦合度(figure 22.2).  figure 22.2: client interaction with subsystem classes after applying the fa?ade pattern 从figure 22.2中我们可以看到:外观对象隔离了客户和子系统对象,从而降低了耦合度。当子系统中的类进行改变时,客户端不会像以前一样受到影响。 尽管客户使用由外观提供的简单接口,但是当需要的时候,客户端还是可以视外观不存在,直接访问子系统中的底层次的接口。这种情况下,它们之间的依赖/耦合度和原来一样。 例子: 让我们建立一个应用: (1) 接受客户的详细资料(账户、地址和信用卡信息) (2) 验证输入的信息 (3) 保存输入的信息到相应的文件中。 这个应用有三个类:account、address和creditcard。每一个类都有自己的验证和保存数据的方法。 listing 22.1: 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; } } listing 22.2: 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; } } listing 22.3: 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; } }  让我们建立一个客户accountmanager,它提供用户输入数据的用户界面。 listing 22.4: 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运行的时候,展示的用户接口如下:  figure 22.4: user interface to enter the customer data 为了验证和保存输入的数据,客户accountmanager需要: (1) 建立account、address和creditcard对象。 (2) 用这些对象验证输入的数据 (3) 用这些对象保存输入的数据。 下面是对象间的交互顺序图:  figure 22.5: how a client would normally interact (directly) with subsystem classes to validate and save the customer data 在这个例子中应用外观模式是一个很好的设计,它可以降低客户和子系统组件(address、account和creditcard)之间的耦合度。应用外观模式,让我们定义一个外观类customerfacade (figure 22.6 and listing 22.5)。它为由客户数据处理类(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()  figure 22.6: fa?ade class to be used by the client in the revised design listing 22.5: customerfacade cl |
|