门面设计模式有很多的应用场景(以后用Facade代替,显得洋气一些:-D),如Tomcat中就有很多的门面设计模式的体现。而为什么需要使用门面设计模式呢?在我看来,就好比一个两个国家要进行交流,没有必要与这两个国家的所有人进行交流,只需要通过外交部与相应的人员进行交流就好。
对于这个解释就是门面设计模式的一个需求——希望封装或隐藏原系统,那么接下来就详细的看下门面设计模式
- Facade的一些概念
- Facade的示例Demo
- Facade在Tomcat中的应用
- 小结
- 参考资料
一、Facade的一些概念
1.1 Facade的描述
在《设计模式》一书中对Facade模式的描述是:
为子系统中的一组接口提供一个统一接口。Facade模式定义了一个更高层的接口,使子系统更加容易使用。
根据这个描述,Facade模式需要一个一致的高层接口。
1.2 一个真实的案例
场景:一个非常庞大、复杂的系统
需求:共同开发一个需要使用该系统的项目
解决:如何使用该系统?
什么样的应用程序接口(API)最适合我们的特殊需求?
结果:这样其他人就能够使用这个新的接口,而无需了解整个复杂的系统了
根据解决的问题:也就是说,我们希望与系统进行隔离,进而使用其中的部分功能,这就是Facade模式(这是Facade的一个场景)。
1.3 Facade的特征
二、Facade示例Demo
根据之前的描述,Facade的示意图如下
2.1 示例DemoOne
实例中具有SubSystemOne.java、SubSystemTwo.java,并通过Facade来将SubSystemOne.java与SubSystemTwo.java封装起来,在FacadeTest.java进行模拟Client调用。
public class SubSystemOne
{
public void describe()
{
System.out.println( "This is SubSystem One!" );
}
}
public class SubSystemTwo
{
public void describe()
{
System.out.println( "The is SubSystem Two!" );
}
}
public class SystemFacade
{
SubSystemOne subOne; //Facade持有子系统对象
SubSystemTwo subTwo; //Facade持有子系统对象
public SystemFacade()
{
this.subOne = new SubSystemOne();
this.subTwo = new SubSystemTwo();
}
public void describeOne()
{
subOne.describe(); //调用子系统One
}
public void describeTwo()
{
subTwo.describe(); //调用子系统Two
}
}
public class FacadeTest
{
@Test
public void testFacadeOne()
{
SystemFacade systemFacade = new SystemFacade();
systemFacade.describeOne();
systemFacade.describeTwo();
}
}
2.2 示例DemoTwo
Facade不仅可以通过方法调用创建更简单的接口,还能用来减少客户必须处理的对象数量。例如,假设有一个Client对象必须处理Database、Model、Element对象。Client必须首先通过Database对象打开数据库,获取Model对象,然后再查询Model对象,获取Element对象,最后请求Element对象的信息。如果能够创建一个可供Client查询的DatabaseFacade,那么Client处理起来将会很容易。
下面有一个简单的示意程序分别表示了没有使用Facade与使用Facade后的情况
public class DB
{
public DB()
{
System.out.println( "DB Open!" );
}
public Model getModel()
{
System.out.println( "Get Model!" );
return new Model();
}
}
public class Model
{
public Element doQuery()
{
System.out.println( "There are some Elements" );
return new Element();
}
}
public class Element
{
public void doAction()
{
System.out.println( "Use Element Do Some Action!" );
}
}
public class DatabaseFacade
{
private DB db;
private Model model;
private Element element;
public DatabaseFacade()
{
this.db = new DB();
}
public void doAction()
{
this.model = db.getModel();
this.element = this.model.doQuery();
this.element.doAction();
}
}
public class FacadeTest
{
@Test
public void testNormalOperation()
{
//获得DB对象
DB db = new DB();
//获得Model对象
Model model = db.getModel();
//获取Element
Element element = model.doQuery();
//do Action
element.doAction();
}
@Test
public void testFacadeOperation()
{
DatabaseFacade databaseFacade = new DatabaseFacade();
databaseFacade.doAction();
}
}
当使用Facade减少Client处理的数量的时候,需要平衡自由度与封装的矛盾。
三、Tomcat中的Facade
Tomcat中有很多用处,例如对Request和Response对象的封装,下面就以此为例来说明下。查看Tomcat 6.0的源码,如下:
apache-tomcat-6.0.37-src\java\javax\servlet\ServletRequest.java
apache-tomcat-6.0.37-src\java\javax\servlet\http\HttpServletRequest.java
apache-tomcat-6.0.37-src\java\org\apache\catalina\connector\Request.java
apache-tomcat-6.0.37-src\java\org\apache\catalina\connector\RequestFacade.java
这四个类的关系,可以通过Tomcat API文档了解
根据之前的讲述,如果说RequestFacade封装了HttpServletRequest,那么在RequestFacade中会有该对象,查看相应的源码可以发现:
这是RequestFacade.java里面有一个Request request = null,在后续的代码中,使用的都是该request对象,那么为什么是一个Request对象,而不是HttpServletRequest对象呢?其实,Request就是HttpServletRequest对象,如下图
RequestFacade所使用的request
RequestFacade后续的Method方法
四、Facade的小结
Facade模式可以应用于下述情况
- 不需要使用一个复杂系统的所有功能,而且可以创建一个新的类,包含访问系统的所有规则。如果只需要使用系统的部分功能,那么你为新类锁创建的API将比原系统的API简单得多。
- 希望封装或者隐藏原系统(Tomcat的很多设计就是出于这个目的)
- 希望使用原系统的功能,而且还希望增加一些功能
- 编写新类的成本小于所有人学会使用或者未来维护原系统上所需的成本
五、参考资料
《设计模式解析》第二版
《大话设计模式》
《深入分析JavaWeb技术内幕》