zoukankan      html  css  js  c++  java
  • 门面模式

    一、定义

    门面模式(Facade Pattern)又叫外观模式,提供了一个统一的接口,用来访问子系统中的一群接口。其主要特征是定义了一个高层接口,让子系统更容易使用,属于结构性模式。其实,在我们日常的编码工作中,经常使用门面模式,但凡只要高层模块需要调度多个子系统(2个以上类对象),我们都会自觉地创建一个新类封装这些子系统,提供精简接口,让高层模块可以更加容易间接调用这些子系统的功能。尤其是现阶段各种第三方SDK,各种开源类库,很大概率都会使用门面模式。 

    门面模式主要包含2种角色:

    外观角色(Facade):也称门面角色,系统对外的统一接口;

    子系统角色(SubSystem):可以同时有一个或多个 SubSystem。每个 SubSytem 都不是一个单独的类,而是一个类的集合。 SubSystem 并不知道 Facade 的存在,对于 SubSystem 而言, Facade 只是另一个客户端而已(即 Facade 对 SubSystem 透明)。

    二、门面模式的应用场景

    SSM架构就是一个很好的门面模式说明,多个业务的调用封装成一个接口给用户调用;

    子系统角色中的类:

    public class ModuleA {
        //示意方法
        public void testA(){
            System.out.println("调用ModuleA中的testA方法");
        }
    }
    public class ModuleB {
        //示意方法
        public void testB(){
            System.out.println("调用ModuleB中的testB方法");
        }
    }
    public class ModuleC {
        //示意方法
        public void testC(){
            System.out.println("调用ModuleC中的testC方法");
        }
    }

    门面角色类:

    public class Facade {
        //示意方法,满足客户端需要的功能
        public void test(){
            ModuleA a = new ModuleA();
            a.testA();
            ModuleB b = new ModuleB();
            b.testB();
            ModuleC c = new ModuleC();
            c.testC();
        }
    }

    客户端角色类:

    public class Client {
     
        public static void main(String[] args) {
            
            Facade facade = new Facade();
            facade.test();
        }
     
    }

    Facade类其实相当于A、B、C模块的外观界面,有了这个Facade类,那么客户端就不需要亲自调用子系统中的A、B、C模块了,也不需要知道系统内部的实现细节,甚至都不需要知道A、B、C模块的存在,客户端只需要跟Facade类交互就好了,从而更好地实现了客户端和子系统中A、B、C模块的解耦,让客户端更容易地使用系统。

    三、源码中的应用

    Spring JDBC模块下的JdbcUtils类,它封装了和JDBC相关的所有操作,像里面的什么closeConnection方法呀,他里面的逻辑调用其实就是个门面模式,他自己啥都没做,事都让Connection 类做了,这里面还有很多方法的调用都这样

    public abstract class JdbcUtils {
        public static final int TYPE_UNKNOWN = -2147483648;
        private static final Log logger = LogFactory.getLog(JdbcUtils.class);
    
        public JdbcUtils() {
        }
    
        public static void closeConnection(@Nullable Connection con) {
            if (con != null) {
                try {
                    con.close();
                } catch (SQLException var2) {
                    logger.debug("Could not close JDBC Connection", var2);
                } catch (Throwable var3) {
                    logger.debug("Unexpected exception on closing JDBC Connection", var3);
                }
            }
    
        }
    
        public static void closeStatement(@Nullable Statement stmt) {
            if (stmt != null) {
                try {
                    stmt.close();
                } catch (SQLException var2) {
                    logger.trace("Could not close JDBC Statement", var2);
                } catch (Throwable var3) {
                    logger.trace("Unexpected exception on closing JDBC Statement", var3);
                }
            }
    
        }
    
        public static void closeResultSet(@Nullable ResultSet rs) {
            if (rs != null) {
                try {
                    rs.close();
                } catch (SQLException var2) {
                    logger.trace("Could not close JDBC ResultSet", var2);
                } catch (Throwable var3) {
                    logger.trace("Unexpected exception on closing JDBC ResultSet", var3);
                }
            }
    
        }
    
        @Nullable
        public static Object getResultSetValue(ResultSet rs, int index, @Nullable Class<?> requiredType) throws SQLException {
            if (requiredType == null) {
                return getResultSetValue(rs, index);
            } else if (String.class == requiredType) {
                return rs.getString(index);
            } else {
                Object value;
                if (Boolean.TYPE != requiredType && Boolean.class != requiredType) {
                    if (Byte.TYPE != requiredType && Byte.class != requiredType) {
                        if (Short.TYPE != requiredType && Short.class != requiredType) {
                            if (Integer.TYPE != requiredType && Integer.class != requiredType) {
                                if (Long.TYPE != requiredType && Long.class != requiredType) {
                                    if (Float.TYPE != requiredType && Float.class != requiredType) {
                                        if (Double.TYPE != requiredType && Double.class != requiredType && Number.class != requiredType) {
                                            if (BigDecimal.class == requiredType) {
                                                return rs.getBigDecimal(index);
                                            }
    
                                            if (Date.class == requiredType) {
                                                return rs.getDate(index);
                                            }
    
                                            if (Time.class == requiredType) {
                                                return rs.getTime(index);
                                            }
    
                                            if (Timestamp.class != requiredType && java.util.Date.class != requiredType) {
                                                if (byte[].class == requiredType) {
                                                    return rs.getBytes(index);
                                                }
    
                                                if (Blob.class == requiredType) {
                                                    return rs.getBlob(index);
                                                }
    
                                                if (Clob.class == requiredType) {
                                                    return rs.getClob(index);
                                                }
    
                                                if (requiredType.isEnum()) {
                                                    Object obj = rs.getObject(index);
                                                    if (obj instanceof String) {
                                                        return obj;
                                                    }
    
                                                    if (obj instanceof Number) {
                                                        return NumberUtils.convertNumberToTargetClass((Number)obj, Integer.class);
                                                    }
    
                                                    return rs.getString(index);
                                                }
    
                                                try {
                                                    return rs.getObject(index, requiredType);
                                                } catch (AbstractMethodError var5) {
                                                    logger.debug("JDBC driver does not implement JDBC 4.1 'getObject(int, Class)' method", var5);
                                                } catch (SQLFeatureNotSupportedException var6) {
                                                    logger.debug("JDBC driver does not support JDBC 4.1 'getObject(int, Class)' method", var6);
                                                } catch (SQLException var7) {
                                                    logger.debug("JDBC driver has limited support for JDBC 4.1 'getObject(int, Class)' method", var7);
                                                }
    
                                                String typeName = requiredType.getSimpleName();
                                                if ("LocalDate".equals(typeName)) {
                                                    return rs.getDate(index);
                                                }
    
                                                if ("LocalTime".equals(typeName)) {
                                                    return rs.getTime(index);
                                                }
    
                                                if ("LocalDateTime".equals(typeName)) {
                                                    return rs.getTimestamp(index);
                                                }
    
                                                return getResultSetValue(rs, index);
                                            }
    
                                            return rs.getTimestamp(index);
                                        }
    
                                        value = rs.getDouble(index);
                                    } else {
                                        value = rs.getFloat(index);
                                    }
                                } else {
                                    value = rs.getLong(index);
                                }
                            } else {
                                value = rs.getInt(index);
                            }
                        } else {
                            value = rs.getShort(index);
                        }
                    } else {
                        value = rs.getByte(index);
                    }
                } else {
                    value = rs.getBoolean(index);
                }
    
                return rs.wasNull() ? null : value;
            }
        }
    
        @Nullable
        public static Object getResultSetValue(ResultSet rs, int index) throws SQLException {
            Object obj = rs.getObject(index);
            String className = null;
            if (obj != null) {
                className = obj.getClass().getName();
            }
    
            if (obj instanceof Blob) {
                Blob blob = (Blob)obj;
                obj = blob.getBytes(1L, (int)blob.length());
            } else if (obj instanceof Clob) {
                Clob clob = (Clob)obj;
                obj = clob.getSubString(1L, (int)clob.length());
            } else if (!"oracle.sql.TIMESTAMP".equals(className) && !"oracle.sql.TIMESTAMPTZ".equals(className)) {
                if (className != null && className.startsWith("oracle.sql.DATE")) {
                    String metaDataClassName = rs.getMetaData().getColumnClassName(index);
                    if (!"java.sql.Timestamp".equals(metaDataClassName) && !"oracle.sql.TIMESTAMP".equals(metaDataClassName)) {
                        obj = rs.getDate(index);
                    } else {
                        obj = rs.getTimestamp(index);
                    }
                } else if (obj instanceof Date && "java.sql.Timestamp".equals(rs.getMetaData().getColumnClassName(index))) {
                    obj = rs.getTimestamp(index);
                }
            } else {
                obj = rs.getTimestamp(index);
            }
    
            return obj;
        }
    
        public static Object extractDatabaseMetaData(DataSource dataSource, DatabaseMetaDataCallback action) throws MetaDataAccessException {
            Connection con = null;
    
            Object var4;
            try {
                con = DataSourceUtils.getConnection(dataSource);
                DatabaseMetaData metaData = con.getMetaData();
                if (metaData == null) {
                    throw new MetaDataAccessException("DatabaseMetaData returned by Connection [" + con + "] was null");
                }
    
                var4 = action.processMetaData(metaData);
            } catch (CannotGetJdbcConnectionException var10) {
                throw new MetaDataAccessException("Could not get Connection for extracting meta data", var10);
            } catch (SQLException var11) {
                throw new MetaDataAccessException("Error while extracting DatabaseMetaData", var11);
            } catch (AbstractMethodError var12) {
                throw new MetaDataAccessException("JDBC DatabaseMetaData method not implemented by JDBC driver - upgrade your driver", var12);
            } finally {
                DataSourceUtils.releaseConnection(con, dataSource);
            }
    
            return var4;
        }
    
        public static <T> T extractDatabaseMetaData(DataSource dataSource, String metaDataMethodName) throws MetaDataAccessException {
            return extractDatabaseMetaData(dataSource, (dbmd) -> {
                try {
                    Method method = DatabaseMetaData.class.getMethod(metaDataMethodName, (Class[])null);
                    return method.invoke(dbmd, (Object[])null);
                } catch (NoSuchMethodException var3) {
                    throw new MetaDataAccessException("No method named '" + metaDataMethodName + "' found on DatabaseMetaData instance [" + dbmd + "]", var3);
                } catch (IllegalAccessException var4) {
                    throw new MetaDataAccessException("Could not access DatabaseMetaData method '" + metaDataMethodName + "'", var4);
                } catch (InvocationTargetException var5) {
                    if (var5.getTargetException() instanceof SQLException) {
                        throw (SQLException)var5.getTargetException();
                    } else {
                        throw new MetaDataAccessException("Invocation of DatabaseMetaData method '" + metaDataMethodName + "' failed", var5);
                    }
                }
            });
        }
    
        public static boolean supportsBatchUpdates(Connection con) {
            try {
                DatabaseMetaData dbmd = con.getMetaData();
                if (dbmd != null) {
                    if (dbmd.supportsBatchUpdates()) {
                        logger.debug("JDBC driver supports batch updates");
                        return true;
                    }
    
                    logger.debug("JDBC driver does not support batch updates");
                }
            } catch (SQLException var2) {
                logger.debug("JDBC driver 'supportsBatchUpdates' method threw exception", var2);
            }
    
            return false;
        }
    
        @Nullable
        public static String commonDatabaseName(@Nullable String source) {
            String name = source;
            if (source != null && source.startsWith("DB2")) {
                name = "DB2";
            } else if ("Sybase SQL Server".equals(source) || "Adaptive Server Enterprise".equals(source) || "ASE".equals(source) || "sql server".equalsIgnoreCase(source)) {
                name = "Sybase";
            }
    
            return name;
        }
    
        public static boolean isNumeric(int sqlType) {
            return -7 == sqlType || -5 == sqlType || 3 == sqlType || 8 == sqlType || 6 == sqlType || 4 == sqlType || 2 == sqlType || 7 == sqlType || 5 == sqlType || -6 == sqlType;
        }
    
        public static String lookupColumnName(ResultSetMetaData resultSetMetaData, int columnIndex) throws SQLException {
            String name = resultSetMetaData.getColumnLabel(columnIndex);
            if (name == null || name.length() < 1) {
                name = resultSetMetaData.getColumnName(columnIndex);
            }
    
            return name;
        }
    
        public static String convertUnderscoreNameToPropertyName(@Nullable String name) {
            StringBuilder result = new StringBuilder();
            boolean nextIsUpper = false;
            if (name != null && name.length() > 0) {
                if (name.length() > 1 && name.substring(1, 2).equals("_")) {
                    result.append(name.substring(0, 1).toUpperCase());
                } else {
                    result.append(name.substring(0, 1).toLowerCase());
                }
    
                for(int i = 1; i < name.length(); ++i) {
                    String s = name.substring(i, i + 1);
                    if (s.equals("_")) {
                        nextIsUpper = true;
                    } else if (nextIsUpper) {
                        result.append(s.toUpperCase());
                        nextIsUpper = false;
                    } else {
                        result.append(s.toLowerCase());
                    }
                }
            }
    
            return result.toString();
        }
    }

    四、总结

    优点:

    1、简化了调用过程,无需深入了解子系统,以防给子系统带来风险。

    2、减少系统依赖、松散耦合

    3、更好地划分访问层次,提高了安全性

    4、遵循迪米特法则,即最少知道原则。

    缺点:

    1、当增加子系统和扩展子系统行为时,可能容易带来未知风险

    2、不符合开闭原则

    3、某些情况下可能违背单一职责原则。

    补充:门面模式其实可以理解为是一种静态代理模式;门面模式的重点是在于封装,静态代理的重点是在于增强功能;


    这短短的一生我们最终都会失去,不妨大胆一点,爱一个人,攀一座山,追一个梦
  • 相关阅读:
    五分钟上手Markdown
    css中居中方法小结
    事务和同步锁
    插入排序
    插入排序
    交换排序
    eclipse 常用快捷键
    交换排序
    二叉搜索树(BST)
    二叉树遍历以及根据前序遍历序列反向生成二叉树
  • 原文地址:https://www.cnblogs.com/xing1/p/14594785.html
Copyright © 2011-2022 走看看