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);
}
}
}
...
具体的操作会由具体的数据库去实现,这里只是统一调用。