外观设计模式

外观设计模式

原文: https://howtodoinjava.com/design-patterns/structural/facade-design-pattern/

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

1.何时使用外观模式

外观模式是结构型设计模式中的一种,另外还有四个设计模式。 当我们有一个复杂的系统要以简化的方式向客户公开时,外观模式是合适的。 其目的是将内部复杂性隐藏在从外部看起来很简单的单个接口后面。

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

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

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

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

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

3.外观设计模式示例

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

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

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

public class ReportHeader {

}

public class ReportFooter {

}

public class ReportData {

}

public enum ReportType 
{
	PDF, HTML
}

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
	}
}

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

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

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

程序输出。

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 外观样式与适配器样式

适配器模式中,我们尝试更改接口,以便客户端可以使用系统。 否则,该系统将很难被客户端使用(甚至无法使用)。

外观模式简化了接口。 它为客户端提供了一个与之交互的简单接口(而不是复杂的子系统)。

4.4 外观模式与中介者模式

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

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

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

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

4.6 外观设计模式的挑战

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

学习愉快!