# 外观设计模式

> 原文： [https://howtodoinjava.com/design-patterns/structural/facade-design-pattern/](https://howtodoinjava.com/design-patterns/structural/facade-design-pattern/)

**外观设计模式**为子系统中的一组接口提供了统一的接口。 外观定义了**更高级别的接口**，使子系统更易于使用。

## 1.何时使用外观模式

外观模式是**结构型设计模式**中的一种，另外还有四个[设计模式](https://howtodoinjava.com/gang-of-four-java-design-patterns/)。 当我们有一个复杂的系统要以简化的方式向客户公开时，外观模式是合适的。 其目的是将内部复杂性隐藏在从外部看起来很简单的单个界面后面。

外观还可以将使用系统的代码与子系统的细节分离开来，从而使以后修改系统变得更加容易。

## 2.现实世界中的外观示例

为了了解外观，让我们举一个非常简单的台式计算机示例。 当我们必须启动计算机时，我们要做的就是按下开始按钮。 我们真的不在乎计算机硬件和软件中包含什么。 这是外观模式的一个示例。

在 Java 编程中，我们必须已连接到数据库以获取一些数据。 我们只是调用方法`dataSource.getConnection()`来获取连接，但是在内部发生了很多事情，例如加载驱动程序，创建连接或从池中获取连接，更新统计信息，然后将连接引用返回给调用者方法。 这是编程世界中外观模式的另一个示例。

同样，我们可以找到更多的示例，这些示例隐藏了许多内部复杂性，并为程序员提供了使用简单的界面来与系统一起工作。 所有这些都是外观示例。

## 3.外观设计模式示例

让我们为演示目的编写自己的外观实现。 在此示例中，我们将创建一个报告生成器，该报告生成器具有多个步骤来创建任何报告。 例如，它将首先创建报告的页眉，页脚，添加数据行，格式化报告，然后以所需的格式（pdf，html 等）编写报告。

使用`ReportGeneratorFacade`，我们将隐藏所有这些步骤并公开易于使用的方法。

```java
public class Report {

	private ReportHeader header;
	private ReportData data;
	private ReportFooter footer;

	public ReportHeader getHeader() {
		return header;
	}
	public void setHeader(ReportHeader header) {
		System.out.println("Setting report header");
		this.header = header;
	}
	public ReportData getData() {
		return data;
	}
	public void setData(ReportData data) {
		System.out.println("Setting report data");
		this.data = data;
	}
	public ReportFooter getFooter() {
		return footer;
	}
	public void setFooter(ReportFooter footer) {
		System.out.println("Setting report footer");
		this.footer = footer;
	}
}

```

```java
public class ReportHeader {

}

```

```java
public class ReportFooter {

}

```

```java
public class ReportData {

}

```

```java
public enum ReportType 
{
	PDF, HTML
}

```

```java
public class ReportWriter {

	public void writeHtmlReport(Report report, String location) {
		System.out.println("HTML Report written");

		//implementation
	}

	public void writePdfReport(Report report, String location) {
		System.out.println("Pdf Report written");

		//implementation
	}
}

```

```java
import javax.activation.DataSource;

public class ReportGeneratorFacade 
{
	public static void generateReport(ReportType type, DataSource dataSource, String location) 
	{
		if(type == null || dataSource == null) 
		{
			//throw some exception
		}
		//Create report
		Report report = new Report();

		report.setHeader(new ReportHeader());
		report.setFooter(new ReportFooter());

		//Get data from dataSource and set to ReportData object

		report.setData(new ReportData());

		//Write report
		ReportWriter writer = new ReportWriter();
		switch(type) 
		{
			case HTML:
				writer.writeHtmlReport(report, location);
				break;

			case PDF:
				writer.writePdfReport(report, location);
				break;
		}
	}
}

```

让我们测试一下外观实现。

```java
import com.howtodoinjava.facade.ReportGeneratorFacade;
import com.howtodoinjava.facade.ReportType;

public class Main 
{
	public static void main(String[] args) throws Exception
	{
		ReportGeneratorFacade reportGeneratorFacade = new ReportGeneratorFacade();

		reportGeneratorFacade.generateReport(ReportType.HTML, null, null);

		reportGeneratorFacade.generateReport(ReportType.PDF, null, null);
	}
}

```

程序输出。

```java
Setting report header
Setting report footer
Setting report data
HTML Report written

Setting report header
Setting report footer
Setting report data
Pdf Report written

```

## 4.常见问题

#### 4.1 外观模式的优点

请记住，外观不会降低复杂性。 它只对外部系统和客户端隐藏它。 因此，外观模式的主要受益者仅是客户端应用和其他系统。

它为客户提供了一个简单的界面，即，我们没有为客户展示一个复杂的子系统，而是为客户提供了一个简化的界面。 它还可以帮助我们减少客户端需要处理的对象数量。

#### 4.2 外观不限制对子系统的访问

外观不封装子系统类或接口。 它只是提供了一个简单的界面（或图层），使我们的生活更轻松。 我们可以自由公开子系统或整个子系统本身的任何功能。

它只会使代码看起来难看，否则它将起作用。

#### 4.3 外观样式与适配器样式

在[适配器模式](https://howtodoinjava.com/design-patterns/structural/adapter-design-pattern-in-java/)中，我们尝试更改接口，以便客户端可以使用系统。 否则，该系统将很难被客户端使用（甚至无法使用）。

外观模式简化了界面。 它为客户端提供了一个与之交互的简单界面（而不是复杂的子系统）。

#### 4.4 外观模式与中介者模式

在中介者模式实现中，子系统知道中介者。 他们互相交谈。

但是在外观中，子系统不了解外观，并且从外观到子系统之间提供了单向通信。

#### 4.5 一个复杂子系统只有一个外观？

一点也不。 我们可以为特定的复杂子系统创建任意数量的外观。 这样做的目的是使系统更易于使用。 它需要创建 N 个外观，然后进行制作。

#### 4.6 外观设计模式的挑战

*   子系统与外观层连接。 因此，您需要注意额外的编码层。
*   当子系统的内部结构发生变化时，您还需要将这些变化合并到外观层中。

学习愉快！