原文: https://howtodoinjava.com/design-patterns/structural/facade-design-pattern/
外观设计模式为子系统中的一组接口提供了统一的接口。 外观定义了更高级别的接口,使子系统更易于使用。
外观模式是结构型设计模式中的一种,另外还有四个设计模式。 当我们有一个复杂的系统要以简化的方式向客户公开时,外观模式是合适的。 其目的是将内部复杂性隐藏在从外部看起来很简单的单个接口后面。
外观还可以将使用系统的代码与子系统的细节分离开来,从而使以后修改系统变得更加容易。
为了了解外观,让我们举一个非常简单的台式计算机示例。 当我们必须启动计算机时,我们要做的就是按下开始按钮。 我们真的不在乎计算机硬件和软件中包含什么。 这是外观模式的一个示例。
在 Java 编程中,我们必须已连接到数据库以获取一些数据。 我们只是调用方法dataSource.getConnection()
来获取连接,但是在内部发生了很多事情,例如加载驱动程序,创建连接或从池中获取连接,更新统计信息,然后将连接引用返回给调用者方法。 这是编程世界中外观模式的另一个示例。
同样,我们可以找到更多的示例,这些示例隐藏了许多内部复杂性,并为程序员提供了使用简单的接口来与系统一起工作。 所有这些都是外观示例。
让我们为演示目的编写自己的外观实现。 在此示例中,我们将创建一个报告生成器,该报告生成器具有多个步骤来创建任何报告。 例如,它将首先创建报告的页眉,页脚,添加数据行,格式化报告,然后以所需的格式(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
请记住,外观不会降低复杂性。 它只对外部系统和客户端隐藏它。 因此,外观模式的主要受益者仅是客户端应用和其他系统。
它为客户提供了一个简单的接口,即,我们没有为客户展示一个复杂的子系统,而是为客户提供了一个简化的接口。 它还可以帮助我们减少客户端需要处理的对象数量。
外观不封装子系统类或接口。 它只是提供了一个简单的接口(或图层),使我们的生活更轻松。 我们可以自由公开子系统或整个子系统本身的任何功能。
它只会使代码看起来难看,否则它将起作用。
在适配器模式中,我们尝试更改接口,以便客户端可以使用系统。 否则,该系统将很难被客户端使用(甚至无法使用)。
外观模式简化了接口。 它为客户端提供了一个与之交互的简单接口(而不是复杂的子系统)。
在中介者模式实现中,子系统知道中介者。 他们互相交谈。
但是在外观中,子系统不了解外观,并且从外观到子系统之间提供了单向通信。
一点也不。 我们可以为特定的复杂子系统创建任意数量的外观。 这样做的目的是使系统更易于使用。 它需要创建 N 个外观,然后进行制作。
- 子系统与外观层连接。 因此,您需要注意额外的编码层。
- 当子系统的内部结构发生变化时,您还需要将这些变化合并到外观层中。
学习愉快!