《Java设计模式》之外观模式

 外观模式(Facade pattern)涉及到子系统的一些类。所谓子系统,是为提供一系列相关的特征(功能)而紧密关联的一组类。例如,一个Account类、Address类和CreditCard类相互关联,成为子系统的一部分,提供在线客户的特征。

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


 

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) 保存输入的信息到相应的文件中。

  这个应用有三个类: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() {

  /*

  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;

 }

}


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运行的时候,展示的用户接口如下:


Figure4: User Interface to Enter the Customer Data

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

  (1) 建立Account、Address和CreditCard对象。

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

  (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和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()


 

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).


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

以上是一个比较全面的例子,另外,为了加深理解我们继续学习下面的内容。

相关角色:

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("关闭摄像头!");
	}
}
 

Light.java

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("关闭感应器!");
	}
}

MyFacade.java

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();
	}
}

ClientTest.java

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
 * 电子邮箱:[email protected]
 * */

public interface ServiceA {
	/**
	 * ServiceA 的A方法
	 * */
	public void methodA() ;
}

package design.facade;

/**
 * 文件名称:ServiceAImpl.java
 * 创建人:Fei Wong
 * 创建时间: Jun 29, 2012
 * 电子邮箱:[email protected]
 * */

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
 * 电子邮箱:[email protected]
 * */

public interface ServiceB {
	/**
	 * ServiceB 的B方法
	 * */
	public void methodB() ;
}

package design.facade;

/**
 * 文件名称:ServiceAImpl.java
 * 创建人:Fei Wong
 * 创建时间: Jun 29, 2012
 * 电子邮箱:[email protected]
 * */

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
 * 电子邮箱:[email protected]
 * */

public interface ServiceC {
	/**
	 * ServiceC 的C方法
	 * */
	public void methodC() ;
}

package design.facade;

/**
 * 文件名称:ServiceAImpl.java
 * 创建人:Fei Wong
 * 创建时间: Jun 29, 2012
 * 电子邮箱:[email protected]
 * */

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
 * 电子邮箱:[email protected]
 *
 * 外观模式 核心类
 * */

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
 * 电子邮箱:[email protected]
 * */

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

版权声明:欢迎转载,希望在你转载的同时,添加原文地址,谢谢配合

时间: 2024-11-04 19:51:44

《Java设计模式》之外观模式的相关文章

java设计模式之外观模式(门面模式)

针对外观模式,在项目开发和实际运用中十分频繁,但是其极易理解,下面就简要介绍一下. 一.概念介绍 外观模式(Facade),他隐藏了系统的复杂性,并向客户端提供了一个可以访问系统的接口.这种类型的设计模式属于结构性模式.为子系统中的一组接口提供了一个统一的访问接口,这个接口使得子系统更容易被访问或者使用. 二.角色及使用场景 简单来说,该模式就是把一些复杂的流程封装成一个接口供给外部用户更简单的使用.这个模式中,设计到3个角色. 1).门面角色:外观模式的核心.它被客户角色调用,它熟悉子系统的功

Java 设计模式:外观模式Facade

Facade 外观模式 外观模式----为子系统的一组接口提供一个统一的界面,此模式定义了一个更高层的接口,这一接口使得子系统更容易使用. 借用<大话设计模式>中的例子:市场上有N多只股票,当股民想要买股票时为了最大化自己的收益需要考察市面上很多种类的股票,然后根据自己的判断选取几只股票组合购买(这种场景下每一只股票都是可以单独购买的,用户需要考察.选取一组股票来一起购买).而有的用户直接购买基金,基金的作用是帮用户选取几只股票来组合购买,用户不用自己去选取多只股票. 在这个场景下:单独的购买

【JAVA设计模式】外观模式(Facade Pattern)

一  定义 为子系统中的一组接口提供一个一致的界面.Facade模式定义了一个高层的接口,这个接口使得这一子系统更加easy使用. 二  案例 一个子系统中拥有3个模块.每一个模块中都有3个方法.当中一个为client调用方法,其它两个则为各子模块间互相调用方法.此时有例如以下需求,client为完毕功能.须要组合3个模块中的方法才干实现功能. 三  未使用模式情况 /** * @Description A模块 * @author jerry * @date 2016年4月11日下午2:16:0

JAVA设计模式之外观模式

外观模式:外观模式为子系统中的各类(或结构与方法)提供一个简明一致的界面,隐藏子系统的复杂性,使子系统更加容易使用.即当子系统复杂或者繁锁时,我们为子系统提供一个接口,其它程序或者对象就通过这个接口与此子系统联系.接口可以是类或方法等.这样就简化了子系统的使用. 简单例子: 1 public interface Camera 2 { 3 public void setPosition(); 4 public void setShutter(); 5 public void setAperture

Java设计模式之外观模式(facade)

随着项目的不断壮大,在controller层会注入数量庞大的service服务,为了降低类与类之间的耦合,提出外观模式,在实际开发中,在原有的层级上添加facade层,在编码过程中, 使facade层作为服务的统一入口,然后再由facede调用其他服务层代码,使得代码结构更清晰. 原文地址:https://www.cnblogs.com/zuok9527/p/11993925.html

浅谈JAVA设计模式之——外观模式

转载请注明出处:http://blog.csdn.net/l1028386804/article/details/45568655 一.概述 为子系统中的一组接口提供一个一致的界面,Facade模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 二.适用性 1.当你要为一个复杂子系统提供一个简单接口时.子系统往往因为不断演化而变得越来越 复杂.大多数模式使用时都会产生更多更小的类.这使得子系统更具可重用性,也更容 易对子系统进行定制,但这也给那些不需要定制子系统的用户带来一些使用上的困

java设计模式_外观模式

package com.wangbiao.design.facade; /**  *   * @Title: Client.java  * @Package com.wangbiao.design.facade  * @Description: TODO   * @author wangbiao     * @date 2014-9-20 下午03:56:08   * @version V1.0  */ public class Client {     public static void m

设计模式之外观模式(九)

设计模式之外观模式 一.引言 当一个复杂的系统由多个复杂的子系统构成,然后客户端调用会调用多个子系统.这时,客户端会和多个子系统耦合在一起,当子系统需要扩展或者改变时,客户端也要随之改变,我们可以使用外观模式将客户端和子系统进行解耦. 二.介绍 意图:为子系统中的一组接口提供一个一致的界面,外观模式定义了一个高层接口,这个接口使得这一子系统更加容易使用. 主要解决:降低访问复杂系统的内部子系统时的复杂度,简化客户端与之的接口. 何时使用: 1.客户端不需要知道系统内部的复杂联系,整个系统只需提供

【设计模式】外观模式

外观模式:它为子系统中的一组接口提供一个统一的高层接口,使得子系统更容易使用.这其实就是一个分层的思想,将较低层复杂的操作交由较高层同一管理,并向用户程序提供简单易用的接口.下面是一个用C++编写的外观模式的例子. #include <iostream> #include <string> using namespace std; // 键盘类 class Keyboard { public: string Type(const string &input) { retur

JAVA设计模式之代理模式

学编程吧JAVA设计模式之代理模式发布了,欢迎通过xuebiancheng8.com来访问 一.概述 给某一个对象提供一个代理,并由代理对象来完成对原对象的访问.代理模式是一种对象结构型模式. 二.适用场景 当无法直接访问某个对象或访问某个对象存在困难时可以通过一个代理对象来间接访问,为了保证客户端使用的透明性,委托对象与代理对象需要实现相同的接口. 三.UML类图 四.参与者 1.接口类:Subject 它声明了真实访问者和代理访问者的共同接口,客户端通常需要针对接口角色进行编程. 2.代理类