Pre
我们先来回顾下门面/外观模式Facade Pattern的定义及基本使用,然后我们在开源软件中来看下是如何实践的。
定义
Facade Pattern 为子系统中的一组接口提供一个一致的入口,该模式定义了一个高层接口,这个接口呢使得第三方更加容易调用该系统,而无需关注内部的细节实现。
案例
有个大项目要搞, 最开始的时候 很小的团队 ,老大带着前端、后端、移动端、集成、测试这几个人一起搞,随着项目越来越复杂,老大是在是忙不过来了,老大要搞清楚每个人的工作,耦合性太高了。。。。。后来老大招了一个项目经理,从此老大只对接项目经理,不关心太细节的东西了,细节的实现由项目经理对接开发人员。
Demo
public class FrontEndGroup { public void frontGaoShiqing(){ System.out.println("FrontEndGroup 搞事情~"); } }
public class BackGroudEndGroup { public void bgGaoShiqing(){ System.out.println("BackGroudEndGroup 搞事情~"); } }
public class MobileAppGroup { public void appGaoShiqing(){ System.out.println("MobileAppGroup 搞事情~"); } }
public class TestGroup { public void testGaoShiqing(){ System.out.println("TestGroup 搞事情~"); } }
V1.0 Boss直接管理
public class Boss { public static void main(String[] args) { FrontEndGroup frontEndGroup = new FrontEndGroup(); BackGroudEndGroup backGroudEndGroup = new BackGroudEndGroup(); MobileAppGroup mobileAppGroup = new MobileAppGroup(); TestGroup testGroup = new TestGroup(); frontEndGroup.frontGaoShiqing(); backGroudEndGroup.bgGaoShiqing(); mobileAppGroup.appGaoShiqing(); testGroup.testGaoShiqing(); } }
V2.0 引入外观类 PmManagerFacade
public class PmManagerFacade { FrontEndGroup frontEndGroup; BackGroudEndGroup backGroudEndGroup; MobileAppGroup mobileAppGroup; TestGroup testGroup; public PmManagerFacade() { frontEndGroup = new FrontEndGroup(); backGroudEndGroup = new BackGroudEndGroup(); mobileAppGroup = new MobileAppGroup(); testGroup = new TestGroup(); } public void pmGaoShiQing() { frontEndGroup.frontGaoShiqing(); backGroudEndGroup.bgGaoShiqing(); mobileAppGroup.appGaoShiqing(); testGroup.testGaoShiqing(); } public void pmGaoShiQing2() { backGroudEndGroup.bgGaoShiqing(); testGroup.testGaoShiqing(); } }
外观类,需要了解所有的要调用的系统的方法或者属性,进行按需组合,以备外部调用。
调用如下
public class Boss { public static void main(String[] args) { PmManagerFacade pmManager = new PmManagerFacade(); pmManager.pmGaoShiQing(); pmManager.pmGaoShiQing2(); } }
main方法就相当于Boss的工作,现在他对接的是外观类Facade , 是不是很符合依赖倒转的原则和迪米特法则的思想【最少知识原则】?
其实我们常用的Controller – Service --Dao 也蕴含了外观模式的思想 。
何时使用Facade
总结一下哈
- 系统设计阶段,要有分层的概念
- 开发阶段,随着系统越来越庞大,可适当增加外观Facade提供简单的接口,减少依赖关系
- 维护老系统,为了屏蔽业务的复杂性(祖传代码,能不动就不动,谁动谁背锅 哈哈哈) ,可以提供一个Facade类,让新对接的系统对接Facade类,Facade负责与遗留代码进行交互,
Tomcat
org.apache.catalina.connector.RequestFacade
看名字 肯定是个外观模式的例子
RequestFacade 和 Request 实现了HttpServletRequest
接口 。
来看下 RequestFacade 包装了Request的啥
/** * The wrapped request. */ protected Request request = null; /** * Construct a wrapper for the specified request. * * @param request The request to be wrapped */ public RequestFacade(Request request) { this.request = request; } @Override public Object getAttribute(String name) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return request.getAttribute(name); } ..... .....
RequestFacade 源码中可以看到,当调用 getAttribute() 方法时,其实还是调用了Request 对象的getAttribute() 方法。
为什么要弄个 RequestFacade 呢 ,其实是为了安全和方便调用,Tomcat 不想暴露过多的方法。
Mybatis
MyBatis的整体架构中, SQLSession负责对外提供服务,屏蔽后面Executor和StatementHandler的复杂处理, 也是一种门面模式
来看下基本用法 就能体会到了
@Test public void sessionTest(){ SqlSession sqlSession = factory.openSession(ExecutorType.REUSE,true); // 门面模式 降低调用复杂性 List<Object> list = sqlSession.selectList("com.artsasin.UserMapper.selectByid", 10); System.out.println(list.get(0)); }
SqlSession 的默认实现是 DefaultSqlSession , DefaultSqlSession 中有个属性 Executor ,屏蔽了外部对Executor的复杂调用,仅和SqlSession交互即可,简化调用。