原文: 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 reportReport report = new Report();report.setHeader(new ReportHeader());report.setFooter(new ReportFooter());//Get data from dataSource and set to ReportData objectreport.setData(new ReportData());//Write reportReportWriter 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 headerSetting report footerSetting report dataHTML Report writtenSetting report headerSetting report footerSetting report dataPdf Report written
4.常见问题
4.1 外观模式的优点
请记住,外观不会降低复杂性。 它只对外部系统和客户端隐藏它。 因此,外观模式的主要受益者仅是客户端应用和其他系统。
它为客户提供了一个简单的接口,即,我们没有为客户展示一个复杂的子系统,而是为客户提供了一个简化的接口。 它还可以帮助我们减少客户端需要处理的对象数量。
4.2 外观不限制对子系统的访问
外观不封装子系统类或接口。 它只是提供了一个简单的接口(或图层),使我们的生活更轻松。 我们可以自由公开子系统或整个子系统本身的任何功能。
它只会使代码看起来难看,否则它将起作用。
4.3 外观样式与适配器样式
在适配器模式中,我们尝试更改接口,以便客户端可以使用系统。 否则,该系统将很难被客户端使用(甚至无法使用)。
外观模式简化了接口。 它为客户端提供了一个与之交互的简单接口(而不是复杂的子系统)。
4.4 外观模式与中介者模式
在中介者模式实现中,子系统知道中介者。 他们互相交谈。
但是在外观中,子系统不了解外观,并且从外观到子系统之间提供了单向通信。
4.5 一个复杂子系统只有一个外观?
一点也不。 我们可以为特定的复杂子系统创建任意数量的外观。 这样做的目的是使系统更易于使用。 它需要创建 N 个外观,然后进行制作。
4.6 外观设计模式的挑战
- 子系统与外观层连接。 因此,您需要注意额外的编码层。
- 当子系统的内部结构发生变化时,您还需要将这些变化合并到外观层中。
学习愉快!
