[design mode summary]

Keywords: Java

Design pattern

Free learning reconstruction
Design pattern RIPtutorial
Graphic command mode

Adapter mode

To sum up: be able to play freely when meeting the third-party framework

Log adaptation third party framework

Assume that the current self-defined code base is as follows. MyLogger has two implementation classes

interface MyLogger {
 void logMessage(String message);
 void logException(Throwable exception);
}
class MyConsoleLogger Implement MyLogger {
    //...
}
class MyFileLogger Implement MyLogger {
    //...
}

When my program needs to introduce a framework to control the Bluetooth connection of my program, the entry class of the Bluetooth framework is as follows

class BluetoothManager {
 private FrameworkLogger logger;
 public BluetoothManager(FrameworkLogger logger) {
 this.logger = logger;
 }
}

interface FrameworkLogger {
 void log(String message);
 void log(Throwable exception);
}

Bluetooth manager accepts a FrameWorkLogger interface, but this interface is completely inconsistent with your current log framework code base. But you want to use your own logging framework, so you use the following classes to meet your needs

class FrameworkLoggerAdapter implements FrameworkLogger {
 private MyLogger logger;
 public FrameworkLoggerAdapter(MyLogger logger) {
 this.logger = logger;
 }
 @Override
 public void log(String message) {
 this.logger.logMessage(message);
 }
 @Override
 public void log(Throwable exception) {
 this.logger.logException(exception);
 }
}

The client can use its own framework normally

FrameworkLogger fileLogger = new FrameworkLoggerAdapter(new MyFileLogger());
BluetoothManager manager = new BluetoothManager(fileLogger);

FrameworkLogger consoleLogger = new FrameworkLoggerAdapter(new MyConsoleLogger());
BluetoothManager manager2 = new BluetoothManager(consoleLogger);
Design patternSolution scenarioConcrete implementation
Adapter modeThe framework uses the framework log class, but I only have my own log classImplement the framework log class and accept your own log class
JDK SWT MouseListener and MouseAdapter

Interface to be adapted - a callback function that listens for events in a UI space

public interface MouseListener extends SWTEventListener {
 public void mouseDoubleClick(MouseEvent e);
 public void mouseDown(MouseEvent e);
 public void mouseUp(MouseEvent e);
}

The interface with adaptation is used normally, so we must implement the three methods in the interface every time. Even if there is no business logic, we need to implement the empty method

obj.addMouseListener(new MouseListener() {
 @Override
 public void mouseDoubleClick(MouseEvent e) {
 }
 @Override
 public void mouseDown(MouseEvent e) {
 }
 @Override
 public void mouseUp(MouseEvent e) {
 // Do the things
 }
});

JDK provides us with an Adapter class

public abstract class MouseAdapter implements MouseListener {
 public void mouseDoubleClick(MouseEvent e) { }
 public void mouseDown(MouseEvent e) { }
 public void mouseUp(MouseEvent e) { }
}
//By providing an empty default implementation, we are free to override only those methods that are of interest in the adapter
obj.addMouseListener(new MouseAdapter() {
 @Override
 public void mouseUp(MouseEvent e) {
 // Do the things
 }
});

Design patternSolution scenarioConcrete implementation
JDK-SWTLISTENERThe framework must use this interface, but I don't want to implement so many interfacesProvide an adapter class implemented by default. If you only care about an interface, you can use the adapter class to implement your own methods

UML diagram todo

Builder pattern

Separate the complex construction process of an object from its representation. In this way, the same construction process can construct different objects

  • Separate the constructed logic from the representation
  • The same construction logic can construct different objects
Builder example

The builder pattern can be used to construct objects with many optional parameters, and the readability will be significantly enhanced

public class Computer {
 public GraphicsCard graphicsCard;
 public Monitor[] monitors;
 public Processor processor;
 public Memory[] ram;
 //more class variables here...
 Computer(GraphicsCard g, Monitor[] m, Processer p, Memory ram) {
 //code omitted for brevity...
 }
 //class methods omitted...
}

If each of the parameters of the above Computer constructor must be passed, this constructor is very good. However, it is assumed that some parameters of the scene are not necessarily passed. You have two choices

  • Use different overloaded constructors
  • The parameters of the constructor can be null. Use null to determine whether to use the default value
    Obviously, the above choices will make your code very bloated, difficult to use and difficult to maintain.


    Builder's ideas for solving problems
  • Create an internal class Builder for the target class
  • For the parameters that must be entered, the constructor of the Builder class forces the input
  • For parameters that do not have to be passed in, the optional implementation is concatenated through the attribute method
  • Finally, call build () to return the object.
public class Computer {
    private GraphicsCard graphicsCard;
    private Monitor[] monitors;
    private Processor processor;
    private Memory[] ram;

    //more class variables here...
    private Computer(Builder builder) {
        this.graphicsCard = builder.graphicsCard;
        this.monitors = builder.monitors;
        this.processor = builder.processor;
        this.ram = builder.ram;
    }

    public GraphicsCard getGraphicsCard() {
        return this.graphicsCard;
    }

    public Monitor[] getMonitors() {
        return this.monitors;
    }

    public Processor getProcessor() {
        return this.processor;
    }

    public Memory[] getRam() {
        return this.ram;
    }

    public static class Builder {
        private GraphicsCard graphicsCard;
        private Monitor[] monitors;
        private Processor processor;
        private Memory[] ram;

        public Builder(Processor p) {
            this.processor = p;
        }

        public Builder graphicsCard(GraphicsCard g) {
            this.graphicsCard = g;
            return this;
        }

        public Builder monitors(Monitor[] mg) {
            this.monitors = mg;
            return this;
        }

        public Builder ram(Memory[] ram) {
            this.ram = ram;
            return this;
        }

        public Computer build() {
            return new Computer(this);
        }
    }
}

Builder mode process

technological processSpecific behavior
Builder classStatic inner class, and copy the properties of the outer class to the inner class
ConstructorThe external class constructor is private, and the Builder class constructor must construct properties
Builder attribute chainThe optional attribute is the attribute chain, and the attribute is given a default value
Construction functionCall the external class constructor and pass the builder property into

Java / Lombok

import lombok.Builder;
@Builder
public class Email {
 private String to;
 private String from;
 private String subject;
 private String body;
}

//example
Email.builder().to("email1@email.com")
 .from("email2@email.com")
 .subject("Email subject")
 .body("Email content")
.build();
Responsibility chain model
  • When the program needs to process different kinds of requests in different ways, and the request type and order are unknown in advance, the responsibility chain mode can be used.
  • This mode can connect multiple processors into a chain. When a request is received, it "asks" each processor whether it can process it. In this way, all processors have the opportunity to process the request.
    The implementation method is shown in the table below
Processing stepsdescribe
Define processor interfaceDeclare the handler interface and describe the signature of the request processing method.
Implement the base class according to the interfaceIn order to eliminate duplicate sample code in a specific handler, you can create an abstract handler base class based on the handler interface.
Implement processor interfaceWhen each handler receives a request, whether to process the request by itself and whether to pass the request along the chain.
Client link definitionObtain pre assembled chains from other objects. In the latter case, you must implement the factory class to create the chain according to the configuration or environment settings.

TODO tomcat source code when learning
Design pattern

Command mode

Command pattern is a behavior design pattern in which an object is used to encapsulate all the information needed to perform an operation or trigger an event later
Principle:
In this way, the command pattern decouples the sender (client) from the receiver through the caller.
The caller will know exactly which command to execute, and the command will know which receiver to call to perform a particular operation.
Command mode

Combination mode

If the core model of the application can be represented by a tree structure, it is valuable to use the combination mode in the application.

Implementation method

  1. Ensure that the core model of the application can be represented in a tree structure. Try to decompose it into simple elements and containers. Remember, containers must be able to contain both simple elements and other containers.

  2. Declare the component interface and its series of methods, which are meaningful to both simple and complex elements.

  3. Create a leaf node class to represent a simple element. There can be multiple different leaf node classes in the program.

  4. Create a container class to represent complex elements. In this class, create an array member variable to store references to its child elements. The array must be able to hold both leaf nodes and containers, so be sure to declare it as a composite interface type.

  5. When implementing component interface methods, remember that the container should leave most of the work to its child elements.

  6. Finally, define methods to add and remove child elements in the container. Remember that these operations can be declared in the component interface. This will violate_ Interface isolation principle, Because these methods in the leaf node class are empty. However, this allows the client to access all elements indiscriminately, even the elements that make up the tree structure.

Here are some examples of combinations from the Java standard library:

java.awt.Container#add(Component) (almost ubiquitous in Swing components)

javax.faces.component.UIComponent#getChildren() (almost ubiquitous in JSF UI components)

Identification method: the combination can be easily identified by putting instances of the same abstract or interface type into the behavior method of the tree structure.

Decorator mode

Identification method: the decoration can be identified by the creation method or constructor with the current class or object as the parameter.

Core class library:

  • java.io.InputStream, Output ­ All code for Stream, Reader, and Writer has constructors that take objects of their own type as parameters.
  • javax.servlet.http.HttpServletRequestWrapper and Http ­ Servlet ­ Response ­ Wrapper
Appearance mode

Appearance mode

example
javax.faces.context.FacesContext uses Life at the bottom ­ Cycle, View ­ Handler and Navigation ­ Handler, but most clients don't know.

javax.faces.context.ExternalContext uses servlets internally ­ Context, Http ­ Session, Http ­ Servlet ­ Request, Http ­ Servlet ­ Response and some other classes.

Identification method: the appearance can be identified by using a simple interface but delegating most of the work to other classes. Typically, appearances manage the full lifecycle of the objects they use.

Sharing element mode

It abandons the way of saving all data in each object. By sharing the same state shared by multiple objects, you can load more objects in limited memory capacity.

Meta mode has only one purpose: to minimize memory consumption. If your program does not experience insufficient memory capacity, you can ignore this mode for the time being.

Examples of meta patterns in core Java Libraries

java.lang.Integer#valueOf(int) 
(as well as Boolean, Byte, Character, Short, Long and BigĀ­Decimal)

Identification method: the shared element can be identified by the construction method. It will return the cached object instead of creating a new object.

proxy pattern

proxy pattern

Difference between agent mode and decoration mode
Decoration and agency have similar structures, but their intentions are very different. The construction of these two patterns is based on the principle of composition, that is, one object should delegate part of its work to another object. The difference between the two is that the agent usually manages the life cycle of its service object, while the generation of decoration is always controlled by the client.

Although the proxy pattern is not common in most Java programs, it is still very convenient in some special cases. This pattern is irreplaceable when you want to add additional behavior to an object of an existing class without modifying the customer code.
example

java.lang.reflect.Proxy
java.rmi.*
javax.ejb.EJB (view comments)
javax.inject.Inject (view comments)
javax.persistence.PersistenceContext

Identification method: the proxy mode delegates all the actual work to some other objects. Unless the proxy is a subclass of a service, each proxy method should finally reference a service object.

Posted by paullb on Sun, 05 Dec 2021 01:39:42 -0800