标签:
外观模式(Facade pattern)涉及到子系统的一些类。所谓子系统,是为提供一系列相关的特征(功能)而紧密关联的一组类。例如,一个Account类、Address类和CreditCard类相互关联,成为子系统的一部分,提供在线客户的特征。
Figure1: Client Interaction with Subsystem Classes before Applying the Facade Pattern |
Figure2: Client Interaction with Subsystem Classes after Applying the Facade Pattern |
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; } } |
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; } } |
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; } } |
Figure3: Subsystem Classes to Provide the Necessary Functionality to Validate and Save the Customer Data |
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 |
Figure4: User Interface to Enter the Customer Data |
Figure5: How a Client Would Normally Interact (Directly) with Subsystem Classes to Validate and Save the Customer Data |
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 |
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; } } } |
Figure7: Class Association with the Fa?ade Class in Place 。 |
Figure 22.8: In the Revised Design, Clients Interact with the Fa?ade Instance to Interface with the Subsystem |
以上是一个比较全面的例子,另外,为了加深理解我们继续学习下面的内容。
相关角色:
1.外观(Facade)角色:客户端可以调用这个角色的方法。此角色知晓相关的子系统的功能和责任。
2.子系统角色:可以同时有一个或者多个子系统。每一个子系统都不是一个单独的类,而是一个类的集合。每一个子系统都可以被客户端直接调用,或者被外观角色调用。
适用情况:
1.为复杂的子系统提供一个简单的接口;
2.客户程序与抽象类的实现部分之间存在着很大的依赖性;
3.构建一个层次结构的子系统时,适用外观模式定义子系统中每层的入口点。
外观模式的简单实现:
代码:
Camara.java
package facade; public class Camara { public void turnOn() { System.out.println("开启摄像头!"); } public void turnOff() { System.out.println("关闭摄像头!"); } }
package facade; public class Light { public void turnOn() { System.out.println("开灯!"); } public void turnOff() { System.out.println("关灯!"); } }
Sensor.java
package facade; public class Sensor { public void activate() { System.out.println("开启感应器!"); } public void deactivate() { System.out.println("关闭感应器!"); } }
package facade; public class MyFacade { private static Camara c1, c2; private static Light l1, l2, l3; private static Sensor s; static { c1 = new Camara(); c2 = new Camara(); l1 = new Light(); l2 = new Light(); l3 = new Light(); s = new Sensor(); } public static void activate() { c1.turnOn(); c2.turnOn(); l1.turnOn(); l2.turnOn(); l3.turnOn(); s.activate(); } public static void deactivate() { c1.turnOff(); c2.turnOff(); l1.turnOff(); l2.turnOff(); l3.turnOff(); s.deactivate(); } }
package facade; public class ClientTest { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub //打开 MyFacade.activate(); //关闭 MyFacade.deactivate(); } }
实际应用中,我们在对付一些老旧的code(尤其是将C的代码转成C++代码)或者即便不是老旧code,但涉及多个子系统时,除了重写全部代码
(对于老旧code而言),我们还可能采用这样一种策略:重新进行类的设计,将原来分散在源码中的类/结构及方法重新组合,形成新的、统一的接口,
供上层应用使用。
这在某种意义上与Adapter及Proxy有类似之处,但是,Proxy(代理)注重在为Client-Subject提供一个访问的中间层,如CORBA可为应
用程序提供透明访问支持,使应用程序无需去考虑平台及网络造成的差异及其它诸多技术细节;Adapter(适配器)注重对接口的转换与调整;而
Facade所面对的往往是多个类或其它程序单元,通过重新组合各类及程序单元,对外提供统一的接口/界面。
Facade模式应用
在遇到以下情况使用Facade模式:
1、当你要为一个复杂子系统提供一个简单接口时。子系统往往因为不断演化而变得越来越复杂。大多数模式使用时都会产生更多更小的类。这使得子系
统更具可重用性,也更容易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困难。
Facade可以提供一个简单的缺省视图,这一视图对大多数用户来说已经足够,而那些需要更多的可定制性的用户可以越过Facade层。
2、客户程序与抽象类的实现部分之间存在着很大的依赖性。引入Facade将这个子系统与客户以及其他的子系统分离,可以提高子系统的独立性和可移
植性。
3、当你需要构建一个层次结构的子系统时,使用Facade模式定义子系统中每层的入口点,如果子系统之间是相互依赖的,你可以让它们仅通过Facade
进行通讯,从而简化了它们之间的依赖关系。
Facade模式优缺点
Facade模式有下面一些优点:
1、它对客户屏蔽子系统组件,因而减少了客户处理的对象的数目并使得子系统使用起来更加方便。
2、它实现了子系统与客户之间的松耦合关系,而子系统内部的功能组件往往是紧耦合的。
松耦合关系使得子系统的组件变化不会影响到它的客户。Facade模式有助于建立层次结构系统,也有助于对对象之间的依赖关系分层。Facade模式可以
消除复杂的循环依赖关系。这一点在客户程序与子系统是分别实现的时候尤为重要。
在大型软件系统中降低编译依赖性至关重要。在子系统类改变时,希望尽量减少重编译工作以节省时间。用Facade可以降低编译依赖性,限制重要系统中较
小的变化所需的重编译工作。Facade模式同样也有利于简化系统在不同平台之间的移植过程,因为编译一个子系统一般不需要编译所有其他的子系统。
3、如果应用需要,它并不限制它们使用子系统类。因此你可以在系统易用性和通用性之间加以选择。
图实例:
package design.facade; /** * 文件名称:ServiceA.java * 创建人:Fei Wong * 创建时间: Jun 29, 2012 * 电子邮箱:feiwong8@126.com * */ public interface ServiceA { /** * ServiceA 的A方法 * */ public void methodA() ; } package design.facade; /** * 文件名称:ServiceAImpl.java * 创建人:Fei Wong * 创建时间: Jun 29, 2012 * 电子邮箱:feiwong8@126.com * */ public class ServiceAImpl implements ServiceA { /* (non-Javadoc) * @see design.facade.ServiceA#methodA() */ @Override public void methodA() { System.out.println( "methodA--> is runing" ); } } package design.facade; /** * 文件名称:ServiceB.java * 创建人:Fei Wong * 创建时间: Jun 29, 2012 * 电子邮箱:feiwong8@126.com * */ public interface ServiceB { /** * ServiceB 的B方法 * */ public void methodB() ; } package design.facade; /** * 文件名称:ServiceAImpl.java * 创建人:Fei Wong * 创建时间: Jun 29, 2012 * 电子邮箱:feiwong8@126.com * */ public class ServiceBImpl implements ServiceB { /* (non-Javadoc) * @see design.facade.ServiceA#methodA() */ @Override public void methodB() { System.out.println( "methodB--> is runing" ); } } package design.facade; /** * 文件名称:ServiceC.java * 创建人:Fei Wong * 创建时间: Jun 29, 2012 * 电子邮箱:feiwong8@126.com * */ public interface ServiceC { /** * ServiceC 的C方法 * */ public void methodC() ; } package design.facade; /** * 文件名称:ServiceAImpl.java * 创建人:Fei Wong * 创建时间: Jun 29, 2012 * 电子邮箱:feiwong8@126.com * */ public class ServiceCImpl implements ServiceC { /* (non-Javadoc) * @see design.facade.ServiceA#methodA() */ @Override public void methodC() { System.out.println( "methodC--> is runing" ); } } package design.facade; /** * 文件名称:Facade.java * 创建人:Fei Wong * 创建时间: Jun 29, 2012 * 电子邮箱:feiwong8@126.com * * 外观模式 核心类 * */ public class Facade { ServiceA sa; ServiceB sb; ServiceC sc; public Facade() { sa = new ServiceAImpl(); sb = new ServiceBImpl(); sc = new ServiceCImpl(); } public void methodA() { sa.methodA(); sb.methodB(); } public void methodB() { sb.methodB(); sc.methodC(); } public void methodC() { sc.methodC(); sa.methodA(); } } package design.facade; /** * 文件名称:Client.java * 创建人:Fei Wong * 创建时间: Jun 29, 2012 * 电子邮箱:feiwong8@126.com * */ public class Client { /** * @param args */ public static void main(String[] args) { ServiceA sa = new ServiceAImpl(); ServiceB sb = new ServiceBImpl(); sa.methodA(); sb.methodB(); System.out.println("====================="); Facade f = new Facade(); f.methodA(); f.methodB(); f.methodC() ; } }
本文借鉴文章:
http://dev.yesky.com/203/2175203.shtml
http://blog.csdn.net/hfmbook/article/details/7702642
http://liyf155.iteye.com/blog/1189789
版权声明:欢迎转载,希望在你转载的同时,添加原文地址,谢谢配合
标签:
原文地址:http://blog.csdn.net/u011225629/article/details/47699233