1、Java设计模式之外观模式研究Java设计模式之外观模式研究 外观模式(Facade pattern)涉及到子系统的一些类。所谓子系统,是为提供一系列相关的特征(功能)而紧密关联的一组类。例如,一个Account类、Address类和CreditCard类相互关联,成为子系统的一部分,提供在线客户的特征。在真实的应用系统中,一个子系统可能由很多类组成。子系统的客户为了它们的需要,需要和子系统中的一些类进行交互。客户和子系统的类进行直接的交互会导致客户端对象和子系统(Figure1)之间高度耦合。任何的类似于对子系统中类的接口的修改,会对依赖于它的所有的客户类造成影响。Figure1: Clie
2、nt Interaction with Subsystem Classes before Applying the Facade Pattern 外观模式(Facade pattern)很适用于在上述情况。外观模式(Facade pattern)为子系统提供了一个更高层次、更简单的接口,从而降低了子系统的复杂度和依赖。这使得子系统更易于使用和管理。外观是一个能为子系统和客户提供简单接口的类。当正确的应用外观,客户不再直接和子系统中的类交互,而是与外观交互。外观承担与子系统中类交互的责任。实际上,外观是子系统与客户的接口,这样外观模式降低了子系统和客户的耦合度(Figure2). Figure2
3、: Client Interaction with Subsystem Classes after Applying the Facade Pattern 从Figure2中我们可以看到:外观对象隔离了客户和子系统对象,从而降低了耦合度。当子系统中的类进行改变时,客户端不会像以前一样受到影响。尽管客户使用由外观提供的简单接口,但是当需要的时候,客户端还是可以视外观不存在,直接访问子系统中的底层次的接口。这种情况下,它们之间的依赖/耦合度和原来一样。 例子:让我们建立一个应用:(1) 接受客户的详细资料(账户、地址和信用卡信息)(2) 验证输入的信息(3) 保存输入的信息到相应的文件中。这个应用
4、有三个类:Account、Address和CreditCard。每一个类都有自己的验证和保存数据的方法。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() /* Lets go wit
5、h 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 getLa
6、stName() 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
7、algorithm could be complex in real-world applications. Lets 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() + ”, + getSt
8、ate(); 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; f
9、inal String CC_DATA_FILE = CC.txt; public CreditCard(String ccType, String ccNumber, String ccExpDate) cardType = ccType; cardNumber = ccNumber; cardExpDate = ccExpDate; public boolean isValid() /* Lets go with simpler validation here to keep the example simpler. */ if (getCardType().equals(AccountM
10、anager.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 fut
11、il = 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 cardE
12、xpDate; 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
13、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 =
14、new JButton(AccountManager.VALIDATE_SAVE); public String getFirstName() return txtFirstName.getText(); /End of class AccountManager 当客户AccountManage运行的时候,展示的用户接口如下:Figure4: User Interface to Enter the Customer Data 为了验证和保存输入的数据,客户AccountManager需要:(1) 建立Account、Address和CreditCard对象。 (2) 用这些对象验证输入的数据(
15、3) 用这些对象保存输入的数据。下面是对象间的交互顺序图:Figure5: How a Client Would Normally Interact (Directly) with Subsystem Classes to Validate and Save the Customer Data 在这个例子中应用外观模式是一个很好的设计,它可以降低客户和子系统组件(Address、Account和CreditCard)之间的耦合度。应用外观模式,让我们定义一个外观类CustomerFacade (Figure6 and Listing5)。它为由客户数据处理类(Address、Account和C
16、reditCard)所组成的子系统提供一个高层次的、简单的接口。 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(inCardNumbe
17、r: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 Stri
18、ng 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;
19、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) car
20、dExpDate = 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);
21、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, cardExp
22、Date); 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方法的形式提
23、供了业务层次上的服务。客户AccountManager不是直接和子系统的每一个组件交互,而是使用了由CustomFacade对象提供的验证和保存客户数据的更高层次、更简单的接口(Figure7).Figure7: Class Association with the Fa?ade Class in Place 。在新的设计中,为了验证和保存客户数据,客户需要:(1) 建立或获得外观对象CustomFacade的一个实例。(2) 传递数据给CustomFacade实例进行验证和保存。(3) 调用CustomFacade实例上的saveCustomData方法。CustomFacade处理创建子系
24、统中必要的对象并且调用这些对象上相应的验证、保存客户数据的方法这些细节问题。客户不再需要直接访问任何的子系统中的对象。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)应用外观的目的是提供一个高层次的接口。因此,外观方法最适合提供特定的高层次的业务服务,而不是进行底层次的单独的业务执行。
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1