2.3 应用程序2
应用程序1中有一个严重的问题。在ServletProcessor1类的process()方法中,必须将ex02.pyrmont.Request的实例向上转型为javax.servlet.ServletRequest实例,将ex02.pyrmont.Response实例向上转型为javax.servlet.ServletResponse实例,然后将它们作为参数传递给servlet的service()方法:
这是不安全的做法,了解这个servlet容器内部工作原理的servlet程序员可以将ServletRequest实例和ServletResponse实例分别向下转型为ex02.pyrmont.Request实例和ex02.pyrmont.Response实例,就可以调用它们各自的公共方法了。有了Request实例后,就可以调用其parse()方法;而有了Response实例后,就可以调用其sendStaticResource()方法。
不能将parse()方法和sendStaticResource()方法设置为私有方法,因为它们会被其他的类调用,但是这两个方法在servlet中不应该是可用的,所以这个方法不好。一种解决方法是将Request类和Response类都设为默认的访问修饰符,这样就不能从ex02.pyrmont包外对它们进行访问了。但是,这里有一个更完美的方法:使用外观类。UML 关系图如图2-2所示。
在第2个应用程序中,添加了两个外观类:RequestFacade和ResponseFacade。RequestFacade类实现servletRequest接口,在其构造函数中需要把它指定的一个Reuqest对象传递给ServletRequest对象引用。ServletRequest接口中每个方法的实现都会调用Request对象的相应方法。但是,ServletRequest对象本身是私有的,无法从类的外部进行访问。相比于将Request对象向上转型为ServletRequest对象,并将其传给service()方法,这里会创建一个RequestFacade对象,再将其传递给service()方法。servlet程序员仍然可以将servletRequest实例向下转型为RequestFacade对象,但它们只能访问ServletRequest接口中提供的方法。现在parse()方法和getUri()方法是安全的了。
代码清单2-7给出了RequestFacade类的定义。
注意RequestFacade类的构造函数,它接受一个Request对象,但立即将其赋给私有的servletRequest对象引用。还要注意的是,RequestFacade中的每个方法会调用servletRequest对象中相对应的方法来执行。
ResponseFacade类的情况与此相同。
应用程序2中共需要使用6个类:
HttpServer2
Request
Response
StaticResourceProcessor
servletProcessor2
Constants
HttpServer2类与HttpServer1类相似,只是在其await()方法中它会使用servletProcessor2类,而不是servletProcessor1类:
servletProcessor2类与servletProcessor1类相似,只是在其process()方法的以下部分中有些许不同:
运行应用程序
要在Windows平台上运行该程序,可以在工作目录下执行如下命令:
java -classpath ./lib/servlet.jar;./ ex02.pyrmont.HttpServer2
在Linux平台上,需要用冒号分割两个库文件:
java -classpath ./lib/servlet.jar:./ ex02.pyrmont.HttpServer2
可以使用与应用程序1相同的URL来测试,结果是相同的。