外观模式(Facade Pattern)

435 查看

《深入剖析Tomcat》(How Tomcat Works),第二章。

创建Request和Response分别实现ServletRequest和ServletResponse,然后将这两个对象传给实现了Servlet接口的PrimitiveServlet类的service方法。

下面代码中的request和response除了实现ServletRequest和ServletResponse接口中的方法,还分别自定义了getUri()和sendStaticResource()方法,如果将他们向上转为ServletRequest和ServletResponse,那么在PrimitiveServlet中如果被向下转为Request和Response,则可以调用getUri和sendStaticResource方法,这被认为是不安全的。

    Request request = ...
    Response response = ...
    servlet = (Servlet) myClass.newInstance();
    servlet.service((ServletRequest) request, (ServletResponse) response);

如果将getUri和sendStaticResource声明为私有,则可以防止在servlet中被调用,但是在其他可能被安全地调用的地方也不能用了,不可以。如果给方法以默认访问权限,则只能在同一个包中访问,这个被认为是可以的,但是不最好,最优雅的方式是通过facade类。

具体做法是定义RequestFacade和ResponseFacade两个类,分别实现ServletRequest和ServletResponse,同时定义私有成员变量Request和Response,并且方法的实现调用Request和Response的实现。然后,将RequestFacade和ResponseFacade上转为ServletRequest和ServletResponse传给servlet的service方法,这样即使在servlet中被下转为RequestFacade和ResponseFacade,也不能访问私有成员变量对象中的方法。既用了Request和Response的实现,又能防止其中自定义的方法被不合理的访问。

类图如下:

代码:

    public class RequestFacade implements ServletRequest {
    
        private ServleLRequest request = null;
        
        public RequestFacade(Request request) {
            this.request = request;
        }
        
        /* implementation of the ServletRequest*/
        public Object getAttribute(String attribute) {
            return request.getAttribute(attribute);
        }
        
        ...
    }
    
    // ResponseFacade类似
    
    RequestFacade requestFacade = new RequestFacade(request);
    ResponseFacade responseFacade = new ResponseFacade(response);
    try {
        servlet = (Servlet) myClass.newInstance();
        servlet.service((ServletRequest) requestFacade,(ServletResponse)responseFacade);
    }

下面是Facade模式的一些内容,与上面的用法不太一样。

  • 定义

外观模式(Facade),为子系统中的一组接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。[DP]

  • 以下来自维基百科

The facade pattern is typically used when:(外观模式的典型用法)

  • a simple interface is required to access a complex system; (需要简单的接口去访问复杂的系统)

  • the abstractions and implementations of a subsystem are tightly coupled;(子系统的抽象和实现是紧密耦合的)

  • need an entry point to each level of layered software; or(需要一个入口去访问分层软件的每一层)

  • a system is very complex or difficult to understand.(一个复杂的,难以理解的系统)

大话设计模式中基金与股票的例子挺好的,这幅图也很好:

下面是维基百科上的示例代码,Java版:

/* Complex parts */

class CPU {
    public void freeze() { ... }
    public void jump(long position) { ... }
    public void execute() { ... }
}

class Memory {
    public void load(long position, byte[] data) { ... }
}

class HardDrive {
    public byte[] read(long lba, int size) { ... }
}

/* Facade */

class ComputerFacade {
    private CPU processor;
    private Memory ram;
    private HardDrive hd;

    public ComputerFacade() {
        this.processor = new CPU();
        this.ram = new Memory();
        this.hd = new HardDrive();
    }

    public void start() {
        processor.freeze();
        ram.load(BOOT_ADDRESS, hd.read(BOOT_SECTOR, SECTOR_SIZE));
        processor.jump(BOOT_ADDRESS);
        processor.execute();
    }
}

/* Client */

class You {
    public static void main(String[] args) {
        ComputerFacade computer = new ComputerFacade();
        computer.start();
    }
}

参考:

  1. 维基百科:https://en.wikipedia.org/wiki...

  2. 大话设计模式第12章 外观模式

  3. How Tomcat Works, 第二章