gogoWebsite

Design Pattern-Appearance Pattern (Facade)

Updated to 17 days ago

Design Pattern-Appearance Pattern (Facade)

    • 1. Overview of appearance mode
      • 1.1 What is Appearance Mode
      • 1.2 Simple implementation of appearance mode
      • 1.3 Things to note when using appearance mode
    • 2. Use of appearance mode
    • 3. Appearance mode implementation method
      • 3.1 Simple Facade Pattern
      • 3.2 Classic Facade Pattern
      • 3.3 Proxy Facade Pattern
      • 3.4 Composite Facade Pattern

Design mode document can be copied without watermark

1. Overview of appearance mode

1.1 What is Appearance Mode

Facade Pattern is a structural design pattern that hides the complexity of the system by providing a consistent interface to multiple complex subsystems, making these subsystems more accessible. The main intention of this pattern is to provide a consistent interface for a set of interfaces in the subsystem, defining a high-level interface, making this subsystem easier to use.

Appearance mode is a design pattern that is often used in daily development. By introducing an appearance role, it simplifies the interaction between the client and the subsystem, provides a unified entry for complex subsystem calls, and reduces the difficulty of using the client.

1.2 Simple implementation of appearance mode

// Define an appearance class
public class Facade {
    private SubSystemA subSystemA;
    private SubSystemB subSystemB;
    private SubSystemC subSystemC;

    public Facade() {
        subSystemA = new SubSystemA();
        subSystemB = new SubSystemB();
        subSystemC = new SubSystemC();
    }

    // Define a simple and easy-to-use interface
    public void operation() {
        subSystemA.operation1();
        subSystemB.operation2();
        subSystemC.operation3();
    }
}

// Define three subsystem classes
class SubSystemA {
    public void operation1() {
        System.out.println("SubSystemA operation1");
    }
}

class SubSystemB {
    public void operation2() {
        System.out.println("SubSystemB operation2");
    }
}

class SubSystemC {
    public void operation3() {
        System.out.println("SubSystemC operation3");
    }
}

In the client code, we just need to create an instance of the appearance class and then call its operation method:

public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.operation(); // Output "SubSystemA operation1", "SubSystemB operation2", "SubSystemC operation3"
    }
}

1.3 Things to note when using appearance mode

  • 1,The key to the appearance pattern is to provide a consistent interface so that clients can interact with the subsystem more easily without understanding the complexity within the subsystem. Therefore, when designing appearance classes, you should try to include all the features that the client may need to use, while avoiding adding unnecessary features.

  • 2, Another thing to note is that although the appearance mode can reduce the coupling between the client and the subsystem, it also increases the coupling between the appearance class and the subsystem. This means that if a module in the subsystem changes, it may also be necessary to modify the appearance class accordingly. Therefore, when using appearance mode, we should minimize the dependence between appearance classes and subsystem classes, so that the subsystem is more independent and flexible.

  • 3, When the number of subsystems increases, appearance classes may become very complex. In this case, it is possible to consider splitting the appearance class into multiple parts, each part responsible for the interface calls of a portion of the subsystem. This not only improves the readability and maintainability of the code, but also makes the coupling between subsystems less.

  • 4, Finally, when using appearance mode, you need to reasonably divide the access levels. For example, some commonly used functions can be placed in high-level interfaces, while less commonly used functions can be placed in the underlying implementation. This not only improves the efficiency of the code, but also reduces the possibility of errors.

2. Use of appearance mode

  • 1, Simplified calling: The appearance mode can simplify the calling process of complex systems, and the client can complete the call without deep understanding of the subsystem. This simplified process reduces the difficulty of using the client and improves the readability and ease of use of the code.

  • 2, Reduced coupling: After using the appearance mode, the client only needs to interact with the appearance object, rather than directly interacting with complex subsystems. This can effectively reduce the dependence between systems, reduce the coupling between systems, and make the subsystem more independent and flexible.

  • 3, Improve security: Since the client does not interact directly with the subsystem, but performs it through appearance classes, it can effectively prevent misoperation of the subsystem and improve the security of the system.

  • 4, Improve flexibility and maintainability: As the number of subsystems increases, appearance classes can become very complex. In this case, it is possible to consider splitting the appearance class into multiple parts, each part responsible for the interface calls of a portion of the subsystem. This not only improves the readability and maintainability of the code, but also makes the coupling between subsystems less.

3. Appearance mode implementation method

3.1 Simple Facade Pattern

// Define an interface
interface SubSystem {
    void operation();
}

// Implement the specific class of interface
class ConcreteSubSystemA implements SubSystem {
    @Override
    public void operation() {
        System.out.println("Execute the operation of subsystem A");
    }
}

class ConcreteSubSystemB implements SubSystem {
    @Override
    public void operation() {
        System.out.println("Execute the operation of subsystem B");
    }
}

class ConcreteSubSystemC implements SubSystem {
    @Override
    public void operation() {
        System.out.println("Execute the operations of subsystem C");
    }
}

// Appearance class, used to encapsulate subsystem calls
class Facade {
    private SubSystem subSystemA;
    private SubSystem subSystemB;
    private SubSystem subSystemC;

    public Facade() {
        subSystemA = new ConcreteSubSystemA();
        subSystemB = new ConcreteSubSystemB();
        subSystemC = new ConcreteSubSystemC();
    }

    public void executeOperation() {
        subSystemA.operation();
        subSystemB.operation();
        subSystemC.operation();
    }
}

// Test code
public class FacadePatternDemo {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.executeOperation(); // Output "Execute the operation of subsystem A", "Execute the operation of subsystem B", "Execute the operation of subsystem C"
    }
}

3.2 Classic Facade Pattern

The classic appearance pattern (Facade Pattern) is a structural design pattern that provides a unified high-level interface for a set of interfaces in a subsystem. Appearance mode defines a high-level interface that makes subsystems easier to use.

Here is an example of a simple Java implementation of classic appearance patterns:

First, we create a class OperatingSystem representing the operating system, which contains some underlying operation methods, such as startup, shutdown, etc.

public class OperatingSystem {
    public void start() {
        System.out.println("Start the operating system");
    }

    public void shutdown() {
        System.out.println("Shut the operating system");
    }
}

Next, we create a Facade class, which also contains some methods for the underlying operation, but to simplify the call, we only provide methods to start and shut down the operating system.

public class Facade {
    private OperatingSystem operatingSystem;

    public Facade() {
        operatingSystem = new OperatingSystem();
    }

    public void start() {
        System.out.println("Skin mode starts to start the operating system");
        operatingSystem.start();
    }

    public void shutdown() {
        System.out.println("Appearance mode starts shutting down the operating system");
        operatingSystem.shutdown();
    }
}

Finally, we use appearance classes in our client code to start and shut down the operating system.

public class Client {
    public static void main(String[] args) {
        Facade facade = new Facade();
        facade.start();
        facade.shutdown();
    }
}

Run the client code and the output result is as follows:

Start the operating system when appearance mode
 Start the operating system
 Appearance mode starts shutting down the operating system
 Turn off the operating system

With this example, we can see that the appearance pattern encapsulates complex subsystem operations in a simple high-level interface, making client code easier to use.

3.3 Proxy Facade Pattern

The proxy appearance pattern is a structural design pattern that provides a unified high-level interface for a set of interfaces in the subsystem. The proxy appearance pattern contains a proxy class and a real class. The proxy class is responsible for communicating between the client and the real class, and the real class is responsible for implementing specific business logic.

Here is an example of a simple Java implementation of proxy appearance pattern:

First, create a real class RealSubject, which implements an interface Subject.

public interface Subject {
    void request();
}

public class RealSubject implements Subject {
    @Override
    public void request() {
        System.out.println("Real topic execution request");
    }
}

Then, create a proxy class Proxy, which also implements the Subject interface. In the proxy class, hold a reference to the real class and call the real class methods in the proxy class methods.

public class Proxy implements Subject {
    private RealSubject realSubject;

    public Proxy(RealSubject realSubject) {
        this.realSubject = realSubject;
    }

    @Override
    public void request() {
        System.out.println("Agent topic performs operations before request");
        realSubject.request();
        System.out.println("Agent topic performs a requested operation");
    }
}

Finally, use the proxy class in the client code to call the methods of the real class.

public class Client {
    public static void main(String[] args) {
        RealSubject realSubject = new RealSubject();
        Proxy proxy = new Proxy(realSubject);
        proxy.request();
    }
}

Run the client code and the output result is as follows:

The proxy topic performs the operation before the request
 Real topic execution request
 The proxy topic performs the requested operation

With this example, we can see that the proxy appearance pattern encapsulates complex subsystem operations in a simple high-level interface, making client code easier to use.

3.4 Composite Facade Pattern

Composite Pattern is a structural design pattern that allows objects to be combined into a tree structure to represent a "part-total" hierarchy. Combining appearance patterns enable client code to be decoupled from the implementation of subsystems, and the entire hierarchy can be handled uniformly.

Here is an example of a simple Java implementation combining appearance patterns:

First, create an abstract component class Component that defines the common interface of the component.

public abstract class Component {
    public void operation() {
    }
}

Then, create a specific component class ConcreteComponent, which implements the Component interface.

public class ConcreteComponent extends Component {
    @Override
    public void operation() {
        System.out.println("Specific component performs operations");
    }
}

Next, create the decorator base class Decorator, which also implements the Component interface and holds a member variable of type Component.

public abstract class Decorator extends Component {
    protected Component component;

    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operation() {
        if (component != null) {
            component.operation();
        }
    }
}

Create specific decorator classes ConcreteDecoratorA and ConcreteDecoratorB, which are inherited from the Decorator class respectively and add additional functionality to the operation method.

public class ConcreteDecoratorA extends Decorator {
    public ConcreteDecoratorA(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedFunction();
    }

    private void addedFunction() {
        System.out.println("Function added by specific decorator A");
    }
}

public class ConcreteDecoratorB extends Decorator {
    public ConcreteDecoratorB(Component component) {
        super(component);
    }

    @Override
    public void operation() {
        super.operation();
        addedFunction();
    }

    private void addedFunction() {
        System.out.println("Function added by specific decorator B");
    }
}

Finally, use the combined appearance pattern in the client code to combine components.

public class Client {
    public static void main(String[] args) {
        Component component = new ConcreteComponent();
        Component decoratorA = new ConcreteDecoratorA(component);
        Component decoratorB = new ConcreteDecoratorB(decoratorA);
        decoratorB.operation();
    }
}

Run the client code and the output result is as follows:

Specific components perform operations
 Specific decoratorsAAdded features
 Specific decoratorsBAdded features

Through this example, we can see that the combined appearance pattern combines specific components and decorators, so that client code can handle the entire hierarchy uniformly.