Hospital example

Modern software systems are relatively complex. A common way for designers to handle complex systems is to "divide and conquer", dividing a system into several smaller subsystems. If a hospital is treated as a subsystem, according to departmental functions, this system can be divided into registration, outpatient, pricing, laboratory testing, payment, medication pickup, etc. Patients seeking treatment have to deal with these departments, just as the client of a subsystem deals with the various classes of the subsystem - it is not an easy task.

First, the patient must register, then go to the outpatient clinic. If the doctor requests a lab test, the patient must first get a price quote, then pay the fee, and only then can go to the laboratory department for the test. After the test, return to the outpatient room. The above figure describes the patient's experience in the hospital; the boxes in the figure represent the hospital.The way to solve this inconvenience is to introduce the Facade pattern. The hospital can set up a receptionist position, and the receptionist is responsible for registering, pricing, paying, picking up medicine, etc. on behalf of the patient. This receptionist is the embodiment of the Facade pattern. The patient only contacts the receptionist, and the receptionist interacts with the various departments.

Structure of the Facade Pattern

The Facade pattern does not have a generalized class diagram description; the best way to describe it is actually to illustrate it with an example.

Since the structure diagram of the Facade pattern is too abstract, let me make it a bit more concrete. Assume there are three modules in the subsystem, namely ModuleA, ModuleB, and ModuleC, each of which has an example method. Then the overall structure diagram of this example is as follows: In this object diagram, two roles appear:
  • Facade role:The client can call methods of this role. This role is aware of the functions and responsibilities of the relevant subsystem(s). Under normal circumstances, this role delegates all requests from the client to the corresponding subsystems.
  • SubSystem role:There can be one or more subsystems at the same time. Each subsystem is not a single class but a collection of classes (for example, the subsystem above is composed of three classes: ModuleA, ModuleB, and ModuleC). Each subsystem can be called directly by the client or called by the facade role. The subsystem does not know about the existence of the facade; for the subsystem, the facade is just another client.

Source code

Classes in the subsystem role:

public class ModuleA {
    //示意方法
    public void testA(){
        System.out.println("调用ModuleA中的testA方法");
    }
}
public class ModuleB {
    //示意方法
    public void testB(){
        System.out.println("调用ModuleB中的testB方法");
    }
}
public class ModuleC {
    //示意方法
    public void testC(){
        System.out.println("调用ModuleC中的testC方法");
    }
}

Facade role class:

public class Facade {
    //示意方法,满足客户端需要的功能
    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 {
 
    public static void main(String[] args) {
        
        Facade facade = new Facade();
        facade.test();
    }
 
}

The Facade class is essentially equivalent to the appearance interface of modules A, B, and C. With this Facade class, the client does not need to personally call modules A, B, and C in the subsystem, nor does it need to know the internal implementation details of the system, nor even the existence of modules A, B, and C. The client only needs to interact with the Facade class, thus better achieving decoupling between the client and modules A, B, and C in the subsystem, making it easier for the client to use the system.

Implementation of the Facade Pattern

Using the Facade pattern also has an additional benefit: methods can be selectively exposed. The methods defined in a module can be divided into two parts: one part is for use outside the subsystem, and the other part is for mutual calls between internal modules of the subsystem. With the Facade class, methods used for mutual calls between internal modules of the subsystem do not need to be exposed outside the subsystem.

For example, define modules A, B, and C as follows.

public class ModuleA {
    /**
     * 提供给子系统外部使用的方法
     */
    public void a1(){};
    
    /**
     * 子系统内部模块之间相互调用时使用的方法
     */
    private void a2(){};
    private void a3(){};
}
public class ModuleB {
    /**
     * 提供给子系统外部使用的方法
     */
    public void b1(){};
    
    /**
     * 子系统内部模块之间相互调用时使用的方法
     */
    private void b2(){};
    private void b3(){};
}
public class ModuleC {
    /**
     * 提供给子系统外部使用的方法
     */
    public void c1(){};
    
    /**
     * 子系统内部模块之间相互调用时使用的方法
     */
    private void c2(){};
    private void c3(){};
}
public class ModuleFacade {
    
    ModuleA a = new ModuleA();
    ModuleB b = new ModuleB();
    ModuleC c = new ModuleC();
    /**
     * 下面这些是A、B、C模块对子系统外部提供的方法
     */
    public void a1(){
        a.a1();
    }
    public void b1(){
        b.b1();
    }
    public void c1(){
        c.c1();
    }
}

In this way, defining a ModuleFacade class can effectively shield internal details, preventing the client from discovering some methods it does not need to know about when calling the Module class. For example, the a2() and a3() methods do not need to be known by the client; otherwise, it would both expose internal details and confuse the client. For the client, they might even have to think about what the a2() and a3() methods are used for. In fact, the a2() and a3() methods are for interaction between internal modules and were never intended for outside the subsystem, so it is better not to let the client know about them.

How many facade classes can a system have?

In the Facade pattern, usually only one facade class is needed, and this facade class has only one instance; in other words, it is a singleton class. Of course, this does not mean there is only one facade class in the entire system; it merely means there is only one facade class for each subsystem. Or, if a system has several subsystems, each subsystem has a facade class, and the entire system can have several facade classes.

Adding new behavior to the subsystem

  

Beginners often think that by inheriting a facade class, new behavior can be added to the subsystem. This is wrong. The purpose of the Facade pattern is to provide a centralized and simplified communication channel for the subsystem, and it cannot add new behavior to the subsystem. For example, the receptionist in a hospital is not medical staff, and the receptionist cannot provide medical services to patients.

Advantages of the Facade Pattern

Loose coupling: The Facade pattern loosens the coupling relationship between the client and the subsystem, making the modules inside the subsystem easier to extend and maintain.

Simple and easy to use: The Facade pattern makes the subsystem easier to use. The client no longer needs to understand the internal implementation of the subsystem, nor does it need to interact with many modules inside the subsystem; it only needs to interact with the facade class.

Better division of access levels: Through reasonable use of Facade, it can help us better divide access levels. Some methods are for outside the system, and some methods are for internal use. Concentrating the functions that need to be exposed to the outside in the facade makes it convenient for clients to use and also effectively hides internal details.

Original URL: https://blog.csdn.net/jason0539/article/details/22775311