大飞带你深入理解Tomcat(三)

本文探讨了在Servlet设计中引入门面模式的重要性,通过封装Request和Response对象,避免了Servlet直接访问底层实现,增强了系统的灵活性和安全性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

上篇代码设计中存在一个设计上的问题:
ServletProcessor类

     Class myClass = loader.loadClass(servletName);
    Servlet servlet= (Servlet) myClass.newInstance();
    //使用servlet调用service方法,servlet处理完成
    servlet.service(request, response);

调用servlet类service方法时,直接将处理类创建request对象跟response对象,传给HelloServlet类的service方法,乍一看好像没啥问题,仔细想想问题就出来:

    //重写service方法,响应请求
    public void service(ServletRequest req, ServletResponse resp)
            throws ServletException, IOException {
        PrintWriter writer = resp.getWriter();
        writer.println("hello, servlet....");
    }

首先,MyTomcat定位是java web服务器,部署在上面的项目,必须按照约定来操作。如果某位心机boy在service方法中对req,跟resp对象进行向下强转,转成MyTomcat定义的Request对象跟Response对象,那么,Request类中的parseRequest parseUri 方法跟Response上面其他方法,就暴露到servlet上了。很明显, 这种设计不合理,服务器不应当对servlet开放这些底层实现的代码。问题来了,那该如何解决?答案就是本篇的主题-外观设计模式(门面设计模式)。

概念(引自百度百科)

门面模式,是指提供一个统一的接口去访问多个子系统的多个不同的接口,它为子系统中的一组接口提供一个统一的高层接口。使得子系统更容易使用。
大白话:你尽管调用接口方法就能实现功能了,具体怎么实现你甭管。

生活例子

撸串
举个例子,
图一:你跟你女票子去撸串,假设你去的是一个自助烤摊,所有操作都得亲力亲为,削签,串肉,烤火的,忙得不亦乐乎,最终烤焦了吃碳,吃力不讨好。
图二:第二你学精了,直接去烧烤店,你跟女票子只需负责点餐即可。所有操作烤店老板帮忙搞掂,你不需要知道老板是怎么削签,串肉,烤火的,你只需负责吃就行咯。

分析:上面的削签,串肉,烤火可以认为是子系统(子系统角色)能提供的功能,烤店老板扮演中间者(门面角色),而你跟女票子就是客户端(客户角色)。你的需求满足,不需要知道削签,串肉,烤火怎么操作,只需要让烤店完成即可。
门面模式(外观模式):门面角色遮蔽了子系统角色的具体功能实现,并按照客户需求对各个子系统功能进行整合,客户完成需求时,调用门面角色提供的外露接口(方法)即可。
门面设计模式
代码列表
facade

public class SystemA {
    public void doSomething() {
        System.out.println("systemA....");
    }
}
public class SystemB {
    public void doSomething() {
        System.out.println("systemB....");
    }
}
public class SystemC {
    public void doSomething() {
        System.out.println("systemB....");
    }
}
public class Client {
    private SystemA a = new SystemA();
    private SystemB b = new SystemB();
    private SystemC c = new SystemC();
    public void show() {
        this.a.doSomething();
        this.b.doSomething();
        this.c.doSomething();
    }
}
public class Client2 {
    //持有门面对象
    private Facade facade = new Facade();
    public void show() {
        facade.toShow();
    }
}

对比Client跟Client2,使用门面模式Client2更加简洁。

了解门面模式后,回到开篇的问题,
Request implements ServletRequest
Response implements ServletResponse

ServletProcessor类中让servlet调用service方法,将实现类request对象/response对象向上转型,当做参数传入在HelloServlet的service方法, 如果有心还是可以反向操作public void service(ServletRequest req, ServletResponse resp), 对req跟resp向下转型成Request / Response 对象, 就这点,在service方法中,已经暴露的request跟response类的实现操作,所以根据门面模式的特征,我们可以抽象出Request跟Response类的门面角色, 对他们具体实现进行遮蔽,仅仅对service暴露完成功能的必须方法即可。
改进设计

public class RequestFacade implements ServletRequest{
    private ServletRequest request;
    public RequestFacade(Request request) {
        this.request = request;
    }

    //其他方法也同样的道理
    public Object getAttribute(String name) {
        return this.request.getAttribute(name);
    }
.....
}

public class ResponseFacade implements ServletResponse{

    private ServletResponse response;
    public ResponseFacade(Response response) {
        this.response = response;
    }

    //其他方法也一样
    public PrintWriter getWriter() throws IOException {
        return response.getWriter();
    }
}
    Class myClass = loader.loadClass(servletName);
    Servlet servlet= (Servlet) myClass.newInstance();
    //使用servlet调用service方法,servlet处理完成
    RequestFacade requestFacade = new RequestFacade(request);
    ResponseFacade responseFacade = new ResponseFacade(response);
    servlet.service(requestFacade, responseFacade);

对应的ServletProcessor类改进service方法传入的门面对象。

分析:
1:RequestFacade ResponseFacade 为什么要实现ServletRequest接口/ServletResponse接口
原因:门面实现对应接口是因为需要知道要将什么方法暴露个servlet,开发允许的方法,遮蔽了世界Reqeust其他是方法实现细节。

到这,本篇结束。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值