The beginning of Dr. Yan Hong's Book JAVA and patterns describes the Facade pattern as follows:
Facade mode is the structure mode of object. The communication between external and a subsystem must be carried out through a unified facade object. Provide a higher-level interface mode to make it easier to use.
Examples of hospitals
Modern software systems are more complex. A common way for designers to deal with complex systems is to "divide and rule", and divide a system into several smaller subsystems. If the hospital is regarded as a subsystem, according to the functions of the Department, this system can be divided into registration, outpatient service, pricing, testing, charging, taking medicine, etc. It is not easy for patients to deal with these departments, just as the client of a subsystem deals with various classes of a subsystem.
First, the patient must be registered first, and then outpatient. If the doctor asks for a test, the patient must first set the price and then pay the fee before he can go to the test department for a test. Return to the clinic after the test.
The above figure describes the experience of patients in the hospital, and the box in the figure represents the hospital.
The way to solve this inconvenience is to introduce the facade mode. The hospital can set up a position for the receptionist, who is responsible for registration, pricing, payment, taking medicine, etc. This receptionist is the embodiment of the facade mode. Patients only contact the receptionist, who deals with various departments.
Structure of facade mode
The facade pattern does not have a general class diagram description, and the best description method is actually illustrated by an example.
Because the structure diagram of facade pattern is too abstract, it is a little more specific. Assuming that there are three modules in the subsystem, namely ModuleA, ModuleB and ModuleC, which have an example method respectively, the overall structure diagram of the example is as follows:
In this object diagram, there are two roles:
● facade role: the client can call the method of this role. This role is aware of the functions and responsibilities of the relevant subsystem (s). Under normal circumstances, this role will delegate all requests sent from the client to the corresponding subsystem.
● subsystem role: there can be one or more subsystems at the same time. Each subsystem is not a separate class, but a collection of classes (for example, the subsystem above is composed of ModuleA, ModuleB and ModuleC). Each subsystem can be called directly by the client or by the facade role. The subsystem does not know the existence of the facade. For the subsystem, the facade is just another client.
source code
Classes in subsystem roles:
public class ModuleA { //Schematic method public void testA(){ System.out.println("call testA method in ModuleA"); } }
public class ModuleB { //Schematic method public void testB(){ System.out.println("call the testB method in ModuleB"); } }
public class ModuleC { //Schematic method public void testC(){ System.out.println("call testC method in ModuleC"); } }
Facade role class:
public class Facade { //Schematic method to meet the functions required by the client public void test(){ ModuleA a = new ModuleA(); a.testA(); ModuleB b = new ModuleB(); b.testB(); ModuleC c = new ModuleC(); c.testC(); } }
Client role class:
public class Client {</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">static</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> main(String[] args) { Facade facade </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> Facade(); facade.test(); }
}
The Facade class is actually equivalent to the appearance interface of modules A, B and C. with this Facade class, the client does not need to call modules A, B and C in the subsystem, nor do they need to know the implementation details inside the system, or even the existence of modules A, B and C. The client only needs to interact with the Facade class, So as to better realize the decoupling of A, B and C modules in the client and subsystem, and make it easier for the client to use the system.
Realization of facade mode
Another added benefit of using Facade patterns is the ability to selectively expose methods. The methods defined in a module can be divided into two parts. One part is used outside the subsystem and the other part is used when the modules inside the subsystem call each other. With the Facade class, the methods used to call each other between modules within the subsystem need not be exposed to the outside of the subsystem.
For example, modules A, B and C are defined as follows.
public class Module { /** *Methods provided for external use of the subsystem */ public void a1(){};</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * The method used when calling each other between modules within the subsystem </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> a2(){}; </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> a3(){};
}
public class ModuleB { /** *Methods provided for external use of the subsystem */ public void b1(){};</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * The method used when calling each other between modules within the subsystem </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> b2(){}; </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> b3(){};
}
public class ModuleC { /** *Methods provided for external use of the subsystem */ public void c1(){};</span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * The method used when calling each other between modules within the subsystem </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> c2(){}; </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> c3(){};
}
public class ModuleFacade {ModuleA a </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ModuleA(); ModuleB b </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ModuleB(); ModuleC c </span>= <span style="color: rgba(0, 0, 255, 1)">new</span><span style="color: rgba(0, 0, 0, 1)"> ModuleC(); </span><span style="color: rgba(0, 128, 0, 1)">/**</span><span style="color: rgba(0, 128, 0, 1)"> * The following are the methods provided by modules A, B and C to the outside of the subsystem </span><span style="color: rgba(0, 128, 0, 1)">*/</span> <span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> a1(){ a.a1(); } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> b1(){ b.b1(); } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> c1(){ c.c1(); }
}
Defining a moduleface class in this way can effectively shield the internal details, so as to prevent the client from finding some methods that it does not need to know when calling the Module class. For example, a2() and a3() methods do not need to be known by the client, otherwise they will not only expose the internal details, but also confuse the client. For the client, he may have to think about what a2() and a3() methods are used for? In fact, a2() and a3() methods interact between internal modules and are not external to the subsystem, so don't let the client know at all.
A system can have several facade classes
In facade mode, only one facade class is usually required, and this facade class has only one instance, in other words, it is a singleton class. Of course, this does not mean that there is only one facade class in the whole system, but only one facade class for each subsystem. In other words, if a system has several subsystems, each subsystem has a facade class, and the whole system can have several facade classes.
Add new behaviors to subsystems
Beginners often think that new behaviors can be added to the subsystem by inheriting a facade class, which is wrong. The purpose of facade mode is to provide a centralized and simplified communication channel for the subsystem, rather than adding new behaviors to the subsystem. For example, the receptionist in the hospital is not a medical staff, and the receptionist cannot provide medical services for patients.
Advantages of facade mode
Advantages of facade mode:
● loose coupling
The facade mode looses the coupling relationship between the client and the subsystem, making it easier for the modules inside the subsystem to expand and maintain.
● easy to use
Facade mode makes the subsystem easier to use. The client no longer needs to understand the implementation inside the subsystem, nor does it need to interact with many modules inside the subsystem. It only needs to interact with facade classes.
● better division of access levels
The rational use of Facade can help us better divide the level of access. Some methods are used outside the system, while others are used inside the system. The functions that need to be exposed to the outside are concentrated in the Facade, which is not only convenient for the client to use, but also hides the internal details.
Application of facade mode in Tomcat
There are many facade patterns in tomcat, because there are many different components in Tomcat. Each component needs to communicate with each other, but it can't expose too much internal data to other components. Using facade patterns to isolate data is a good way.
The following is the facade mode used on the Request:
Anyone who has used servlets knows, except on the web In addition to the corresponding configuration of XML, you also need to inherit an abstract class called HttpServlet and rewrite doGet and doPost methods (of course, it is also possible to rewrite only service methods).
public class TestServlet extends HttpServlet {</span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> doGet(HttpServletRequest request, HttpServletResponse response) </span><span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException { </span><span style="color: rgba(0, 0, 255, 1)">this</span><span style="color: rgba(0, 0, 0, 1)">.doPost(request, response); } </span><span style="color: rgba(0, 0, 255, 1)">public</span> <span style="color: rgba(0, 0, 255, 1)">void</span><span style="color: rgba(0, 0, 0, 1)"> doPost(HttpServletRequest request, HttpServletResponse response) </span><span style="color: rgba(0, 0, 255, 1)">throws</span><span style="color: rgba(0, 0, 0, 1)"> ServletException, IOException { }
}
It can be seen that doGet and doPost methods have two parameters. The parameter types are interface HttpServletRequest and interface HttpServletResponse. What is the real type passed from Tomcat? Through debug ging, you will find that there are many methods in Tomcat before calling the TestServlet class. As shown in the figure below
Note the class in the red box. The 225 line code of the invoke method in the StandardWrapperValue class is as follows:
filterChain.doFilter (request.getRequest(), response.getResponse());
In the StandardWrapperValue class, the Request object and Response object are not directly passed to the doFilter method of the ApplicationFilterChain class. Instead, the RequestFacade and ResponseFacade objects are passed. Why do you say so? Take a look at Request Getrequest () and Response The getresponse () method reveals the truth.
Request class
public HttpServletRequest getRequest() { if (facade == null) { facade = new RequestFacade(this); } return facade; }
Response class
public HttpServletResponse getResponse() { if (facade == null) { facade = new ResponseFacade(this); } return (facade); }
You can see that they all return a facade class, so what are the benefits of doing so?
Many methods in the Request object are used when internal components interact with each other, such as setComet, setRequestedSessionId and other methods (not listed here). These methods are not exposed externally, but they must be set to public, because they also need to be used interactively with internal components. The best solution is to use a Facade class to shield the methods used in interaction with internal components and only provide them to the methods of interest to external programs.
If you do not use the Facade class and directly pass the Request object and Response object, programmers familiar with the internal operation of the container can respectively convert the ServletRequest and ServletResponse objects down to Request and Response, and call their public methods. For example, if you have a Request object, you can call setComet, setRequestedSessionId and other methods, which will endanger security.