1 应用门面模式整合已知API的性能
个别的电商平台都是整合泛滥的子系统聚合到一起造成一个大型的购物平台,个别状况下,有很多现成的性能都不是从新开发的,而是要去对接已有的各个子系统,这些子系统可能波及积分零碎、领取零碎、物流零碎的接口调用。如果所有的接口调用全副由前端发送网络申请去调用现有接口,一则会减少前端开发人员的难度,二则会减少一些网络申请,影响页面性能。此时就能够施展门面模式的劣势了。将所有现成的接口全副整合到一个类中,由后端提供对立的接口供前端调用,这样前端开发人员就不须要关怀各接口的业务关系,只须要把精力集中在页面交互上。咱们用代码来模仿一个积分兑换礼品的业务场景。
首先创立礼品的实体类GiftInfo。
<code class="java"> public class GiftInfo { private String name; public GiftInfo(String name) { this.name = name; } public String getName() { return name; } }
而后编写各个子系统的业务逻辑代码,创立积分零碎QualifyService类。
<code class="java"> public class QualifyService { public boolean isAvailable(GiftInfo giftInfo){ System.out.println("校验" + giftInfo.getName() + " 积分资格通过,库存通过"); return true; } }
创立领取零碎PaymentService类。
<code class="java"> public class PaymentService { public boolean pay(GiftInfo pointsGift){ //扣减积分 System.out.println("领取" + pointsGift.getName() + " 积分胜利"); return true; } }
创立物流零碎ShippingService类。
<code class="java"> public class ShippingService { //发货 public String delivery(GiftInfo giftInfo){ //物流零碎的对接逻辑 System.out.println(giftInfo.getName() + "进入物流零碎"); String shippingOrderNo = "666"; return shippingOrderNo; } }
接着创立外观角色GiftFacadeService类,对外只凋谢一个兑换礼物的exchange()办法,在exchange()办法外部整合3个子系统的所有性能。
<code class="java"> 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); } } } }
最初来看客户端代码。
<code class="java"> 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相干的所有操作,代码片段如下。
<code class="java"> 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结尾的办法,源码如下。
<code class="java"> 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类为例,来看其源码。
<code class="java"> 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弹架构:30个设计模式实在案例,挑战年薪60W不是梦
本文为“Tom弹架构”原创,转载请注明出处。技术在于分享,我分享我高兴!
如果本文对您有帮忙,欢送关注和点赞;如果您有任何倡议也可留言评论或私信,您的反对是我保持创作的能源。关注微信公众号『 Tom弹架构 』可获取更多技术干货!