|
|
|
| 您的位置:首页>>设计模式>>外观模式(Faccedil;adenbsp;pattern) |
|
|
外观模式(Faccedil;adenbsp;pattern)
|
| 2007-04-13 来源:www.javaresearch.org 作者:未知 |
本文是翻译《Software Architecture Design Patterns in Java》一书,我将陆续为大家翻译其他章节,希望大家支持指正!
第22章:外观模式(Façade pattern) 描述: 外观模式(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;
- }
- }
Figure 22.3: Subsystem Classes to Provide the Necessary Functionality to Validate and Save the Customer Data 让我们建立一个客户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 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对象提供的验证和保存客户数据的更高层次、更简单的接口(Figure 22.7). Figure 22.7: Class Association with the Façade Class in Place 。 在新的设计中,为了验证和保存客户数据,客户需要: (1) 建立或获得外观对象CustomFacade的一个实例。 (2) 传递数据给CustomFacade实例进行验证和保存。 (3) 调用CustomFacade实例上的saveCustomData方法。 CustomFacade处理创建子系统中必要的对象并且调用这些对象上相应的验证、保存客户数据的方法这些细节问题。客户不再需要直接访问任何的子系统中的对象。 Figure 22.8展示了新的设计的消息流图:
Figure 22.8: In the Revised Design, Clients Interact with the Façade Instance to Interface with the Subsystem
重要提示: 下面是应用外观模式的注意事项: (1) 在设计外观时,不需要增加额外的功能。 (2) 不要从外观方法中返回子系统中的组件给客户。例如:有一个下面的方法: CreditCard getCreditCard() 会报漏子系统的细节给客户。应用就不能从应用外观模式中取得最大的好处。 (3)应用外观的目的是提供一个高层次的接口。因此,外观方法最适合提供特定的高层次的业务服务,而不是进行底层次的单独的业务执行。 附件为本文的代码和原文!请大家指正!附件:26.rar(5K) 附件:Chapter_22.doc(273K)
|
|
|
| |