外观模式,又叫门面模式 (符合迪米特法则,也就是最少知道原则, 不改让用户知道的,就别让其知道)
外观模式定义了高层的接口,子系统负责去实现
定义一个优秀的结构很重要
用户通过调用高层接口(门面),来达到自己的目的,而接口的实现是交给子系统去完成
用户不需要知道有哪些子系统(实现类或者是其他的类)
门面模式的使用场景:
子系统复杂,使用外观模式,提供统一简单调用的接口(架构师定义接口,由码农去实现)
目的:构建多层系统结构,利用外观对象作为每层的入口,简化层之间的调用
优点: 简化调用过程,无需了解深入子系统,防止带来风险
也减少了系统以来,降低耦合
提供更好的划分访问层次
外观模式的缺点:
增加子系统,扩展子系统行为容易引入风险
也不符合开闭原则
和外观模式相关的设计模式:
- 中介者模式(外观关注的是系统对外提供的接口(对外交互),而中介者是系统内部交互)
- 单例模式 (外观对象可以是一个单例对象)
- 抽象工厂模式 (外观类可以是一个抽象工厂,去获得子系统相关的实现(接口的实现类)) 比如 Logger log = LoggerFactory.getLogger(A.class); 子系统通过外观类,屏蔽了外部的访问,调用者无需关注实现
门面模式 在 tomcat,mybatis 以及 jdbcTemplate中 都有很好的应用
比如 tomcat 中的 RequestFacade implements HttpServletRequest
ctrl +n > 输入 requestFacade
可以看到优秀的设计,综合了 Façade和 装饰者模式
转到 JdbcUtils 代码下面
@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; } }
这个jdbcUtils 对 jdbc 进行了封装,在开发中,我们不需要关注怎么操作,直接用这个 jdbcUtils 即可
都是对原生 jdbc的封装
mybatis 的Configuration 中也是这样
Configuration 还结合 工厂模式, 通过这个工厂创建对应的实现类(实现了某个接口),然后返回给用户