写点什么

意外发现,原来你不知道自己每天都在用门面模式

作者:Tom弹架构
  • 2021 年 11 月 13 日
  • 本文字数:4028 字

    阅读完需:约 13 分钟

本文节选自《设计模式就该这样学》

1 使用门面模式整合已知 API 的功能

一般的电商平台都是整合众多的子系统聚合到一起形成一个大型的购物平台,一般情况下,有很多现成的功能都不是重新开发的,而是要去对接已有的各个子系统,这些子系统可能涉及积分系统、支付系统、物流系统的接口调用。如果所有的接口调用全部由前端发送网络请求去调用现有接口,一则会增加前端开发人员的难度,二则会增加一些网络请求,影响页面性能。此时就可以发挥门面模式的优势了。将所有现成的接口全部整合到一个类中,由后端提供统一的接口供前端调用,这样前端开发人员就不需要关心各接口的业务关系,只需要把精力集中在页面交互上。我们用代码来模拟一个积分兑换礼品的业务场景。首先创建礼品的实体类 GiftInfo。



public class GiftInfo { private String name;
public GiftInfo(String name) { this.name = name; }
public String getName() { return name; }}
复制代码


然后编写各个子系统的业务逻辑代码,创建积分系统 QualifyService 类。



public class QualifyService { public boolean isAvailable(GiftInfo giftInfo){ System.out.println("校验" + giftInfo.getName() + " 积分资格通过,库存通过"); return true; }}
复制代码


创建支付系统 PaymentService 类。



public class PaymentService { public boolean pay(GiftInfo pointsGift){ //扣减积分 System.out.println("支付" + pointsGift.getName() + " 积分成功"); return true; }}
复制代码


创建物流系统 ShippingService 类。



public class ShippingService {
//发货 public String delivery(GiftInfo giftInfo){ //物流系统的对接逻辑 System.out.println(giftInfo.getName() + "进入物流系统"); String shippingOrderNo = "666"; return shippingOrderNo; }}
复制代码


接着创建外观角色 GiftFacadeService 类,对外只开放一个兑换礼物的 exchange()方法,在 exchange()方法内部整合 3 个子系统的所有功能。



public class GiftFacadeService { private QualifyService qualifyService = new QualifyService(); private PaymentService pointsPaymentService = new PaymentService(); private ShippingService shippingService = new ShippingService();
//兑换 public void exchange(GiftInfo giftInfo){ if(qualifyService.isAvailable(giftInfo)){ //资格校验通过 if(pointsPaymentService.pay(giftInfo)){ //如果支付积分成功 String shippingOrderNo = shippingService.delivery(giftInfo); System.out.println("物流系统下单成功,订单号是:"+shippingOrderNo); } } }}
复制代码


最后来看客户端代码。



public static void main(String[] args) { GiftInfo giftInfo = new GiftInfo("《Spring 5核心原理》"); GiftFacadeService giftFacadeService = new GiftFacadeService(); giftFacadeService.exchange(giftInfo);}
复制代码


运行结果如下图所示。



通过这样一个案例对比,相信大家对门面模式的印象就非常深刻了。

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

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



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(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(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(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); } }
} ...}
复制代码


更多其他操作,看它的结构就非常清楚了,如下图所示。


3 门面模式在 MyBatis 源码中的应用

再来看一个 MyBatis 中的 Configuration 类,其中有很多 new 开头的方法,源码如下。



public MetaObject newMetaObject(Object object) { return MetaObject.forObject(object, this.objectFactory, this.objectWrapperFactory, this.reflectorFactory); }
public ParameterHandler newParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) { ParameterHandler parameterHandler = mappedStatement.getLang().createParameterHandler(mappedStatement, parameterObject, boundSql); parameterHandler = (ParameterHandler)this.interceptorChain.pluginAll(parameterHandler); return parameterHandler; }
public ResultSetHandler newResultSetHandler(Executor executor, MappedStatement mappedStatement, RowBounds rowBounds, ParameterHandler parameterHandler, ResultHandler resultHandler, BoundSql boundSql) { ResultSetHandler resultSetHandler = new DefaultResultSetHandler(executor, mappedStatement, parameterHandler, resultHandler, boundSql, rowBounds); ResultSetHandler resultSetHandler = (ResultSetHandler)this.interceptorChain.pluginAll (resultSetHandler); return resultSetHandler; }
public StatementHandler newStatementHandler(Executor executor, MappedStatement mappedStatement, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler, BoundSql boundSql) { StatementHandler statementHandler = new RoutingStatementHandler(executor, mappedStatement, parameterObject, rowBounds, resultHandler, boundSql); StatementHandler statementHandler = (StatementHandler)this.interceptorChain.pluginAll (statementHandler); return statementHandler; }
public Executor newExecutor(Transaction transaction) { return this.newExecutor(transaction, this.defaultExecutorType);}
复制代码


上面这些方法都是对 JDBC 中关键组件操作的封装。

4 门面模式在 Tomcat 源码中的应用

另外,门面模式在 Tomcat 的源码中也有体现,也非常有意思。以 RequestFacade 类为例,来看其源码。



public class RequestFacade implements HttpServletRequest {...@Override public String getContentType() {
if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); }
return request.getContentType(); }

@Override public ServletInputStream getInputStream() throws IOException {
if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); }
return request.getInputStream(); }

@Override public String getParameter(String name) {
if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); }
if (Globals.IS_SECURITY_ENABLED){ return AccessController.doPrivileged( new GetParameterPrivilegedAction(name)); } else { return request.getParameter(name); } }...}
复制代码


从名字就知道它用了门面模式。它封装了非常多的 request 操作,也整合了很多 servlet-api 以外的内容,给用户使用提供了很大便捷。同样,Tomcat 针对 Response 和 Session 也封装了对应的 ResponseFacade 类和 StandardSessionFacade 类,感兴趣的小伙伴可以深入了解一下。


小伙伴们是不是意外地发现,你每天都在用门面模式?


关注微信公众号『 Tom 弹架构 』回复“设计模式”可获取完整源码。


【推荐】Tom弹架构:30个设计模式真实案例,挑战年薪60W不是梦


本文为“Tom 弹架构”原创,转载请注明出处。技术在于分享,我分享我快乐!

如果本文对您有帮助,欢迎关注和点赞;如果您有任何建议也可留言评论或私信,您的支持是我坚持创作的动力。关注微信公众号『 Tom 弹架构 』可获取更多技术干货!

发布于: 2 小时前阅读数: 7
用户头像

Tom弹架构

关注

不只做一个技术者,更要做一个思考者 2021.10.22 加入

畅销书作者,代表作品: 《Spring 5核心原理与30个类手写实战》 《Netty 4核心原理与手写RPC框架实战》 《设计模式就该这样学》

评论

发布
暂无评论
意外发现,原来你不知道自己每天都在用门面模式