外观设计模式

62 阅读3分钟

GoF

Provide a unified interface to a set of interfaces in a subsystem.Facade definesa higher-level interface that makes the subsystem easier to use. 为子系统中的 一组接口提供统一的接口。Facade Pattern定义了使子系统更易于使用的高级接口。

Facade design pattern is used to help client applications to easily interact with the system. Facade设计模式用于帮助客户端应用程序轻松地与系统交互。

原因是: 假设我们有一个应用程序,它有一组接口,不同的接口集来处理不同类型的数据库。并生成不同类型的报告,如HTML报告、PDF报告等。当 接口复杂性增加或 接口名字起不好看不懂时,会很令人困惑,客户端应用程序会发现很难管理它。 在这里插入图片描述

外观模式的应用场景

外观模式也叫门面模式。 在日常生活中,门面模式也是很常见的。 比如,我们去医院就诊,很多医院都设置了导诊台,这个导诊台就好比一个门面。有了这个导诊台,我们全程就诊都不需要到处乱转,就诊路线变得非常清楚。

在软件系统中,门面模式适用于以下应用场景。 (1)为一个复杂的模块或子系统提供一个简洁的供外界访问的接口。 (2)希望提高子系统的独立性时。 (3)当子系统由于不可避免的暂时原因导致可能存在Bug或性能相关问题时,可以通过门面模式提供一个高层接口,隔离客户端与子系统的直接交互,预防代码污染。

在这里插入图片描述 provide a wrapper interface on top of the existing interface to help client application.

Set of Interfaces

public class A1_MySqlHelper {
	public static Connection getMySqlDBConnection() {
		// get MySql DB connection using connection parameters
		return null;
	}
	public void generateMySqlPDFReport(String tableName, Connection con) {
		// get data from table and generate pdf report
		System.out.println("生成  MySql PDF"+tableName +"Report");
	}
	public void generateMySqlHTMLReport(String tableName, Connection con) {
		// get data from table and generate html report
		System.out.println("生成  MySql HTML"+tableName +"Report");
	}
}
public class A2_OracleHelper {
	public static Connection getOracleDBConnection(){
		//get Oracle DB connection using connection parameters
		return null;
	}
	public void generateOraclePDFReport(String tableName, Connection con){
		//get data from table and generate pdf report
		System.out.println("生成  Oracle PDF"+tableName +"Report");
	}
	public void generateOracleHTMLReport(String tableName, Connection con){
		//get data from table and generate html report
		System.out.println("生成  Oracle PDF"+tableName +"Report");
	}
}

unified interface

public class A3_HelperFacade {
	public static void generateReport(DBTypes dbType, ReportTypes reportType, String tableName){
		Connection con = null;
		switch (dbType){
		case MYSQL: 
			con = A1_MySqlHelper.getMySqlDBConnection();
			A1_MySqlHelper mySqlHelper = new A1_MySqlHelper();
			switch(reportType){
			case HTML:
				mySqlHelper.generateMySqlHTMLReport(tableName, con);
				break;
			case PDF:
				mySqlHelper.generateMySqlPDFReport(tableName, con);
				break;
			}
			break;
		case ORACLE: 
			con = A2_OracleHelper.getOracleDBConnection();
			A2_OracleHelper oracleHelper = new A2_OracleHelper();
			switch(reportType){
			case HTML:
				oracleHelper.generateOracleHTMLReport(tableName, con);
				break;
			case PDF:
				oracleHelper.generateOraclePDFReport(tableName, con);
				break;
			}
			break;
		}
	}
	public static enum DBTypes{
		MYSQL,ORACLE;
	}
	public static enum ReportTypes{
		HTML,PDF;
	}
}

使用

		String tableName="Employee";
		
		//generating MySql HTML report and Oracle PDF report without using Facade
		Connection con = A1_MySqlHelper.getMySqlDBConnection();
		A1_MySqlHelper mySqlHelper = new A1_MySqlHelper();
		mySqlHelper.generateMySqlHTMLReport(tableName, con);
		
		Connection con1 = A2_OracleHelper.getOracleDBConnection();
		A2_OracleHelper oracleHelper = new A2_OracleHelper();
		oracleHelper.generateOraclePDFReport(tableName, con1);
		
		System.out.println("**************************");
		
		//generating MySql HTML report and Oracle PDF report using Facade
		A3_HelperFacade.generateReport(A3_HelperFacade.DBTypes.MYSQL, A3_HelperFacade.ReportTypes.HTML, tableName);
		A3_HelperFacade.generateReport(A3_HelperFacade.DBTypes.ORACLE, A3_HelperFacade.ReportTypes.PDF, tableName);

结构

生成  MySql HTMLEmployeeReport
生成  Oracle PDFEmployeeReport
**************************
生成  MySql HTMLEmployeeReport
生成  Oracle PDFEmployeeReport

避免在客户端有 大量逻辑的 更简单和 更清晰的方法。 JDBC Driver Manager类获得数据库连接是外观设计模式的一个很好的例子

门面模式在Spring源码中的应用

先来看Spring JDBC模块下的JdbcUtils类,它封装了与JDBC相关的所有操作,代码片段如下。

public abstract class JdbcUtils {
...
	public static void closeConnection(Connection con) {
		if (con != null) {
			try {
				con.close();
			}
			catch (SQLException ex) {
				logger.debug("Could not close JDBC Connection", ex);
			}
			catch (Throwable ex) {
				// We don't trust the JDBC driver: It might throw RuntimeException or Error.
				logger.debug("Unexpected exception on closing JDBC Connection", ex);
			}
		}
	}
	public static void closeStatement(Statement stmt) {
		if (stmt != null) {
			try {
				stmt.close();
			}
			catch (SQLException ex) {
				logger.trace("Could not close JDBC Statement", ex);
			}
			catch (Throwable ex) {
				// We don't trust the JDBC driver: It might throw RuntimeException or Error.
				logger.trace("Unexpected exception on closing JDBC Statement", ex);
			}
		}
	}
	public static void closeResultSet(ResultSet rs) {
		if (rs != null) {
			try {
				rs.close();
			}
			catch (SQLException ex) {
				logger.trace("Could not close JDBC ResultSet", ex);
			}
			catch (Throwable ex) {
				// We don't trust the JDBC driver: It might throw RuntimeException or Error.
				logger.trace("Unexpected exception on closing JDBC ResultSet", ex);
			}
		}
	}
...

具体的操作会由具体的数据库去实现,这里只是统一调用。