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 pattern | Solution scenario | Concrete implementation |
---|---|---|
Adapter mode | The framework uses the framework log class, but I only have my own log class | Implement 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 pattern | Solution scenario | Concrete implementation |
---|---|---|
JDK-SWTLISTENER | The framework must use this interface, but I don't want to implement so many interfaces | Provide an adapter class implemented by default. If you only care about an interface, you can use the adapter class to implement your own methods |
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 process | Specific behavior |
---|---|
Builder class | Static inner class, and copy the properties of the outer class to the inner class |
Constructor | The external class constructor is private, and the Builder class constructor must construct properties |
Builder attribute chain | The optional attribute is the attribute chain, and the attribute is given a default value |
Construction function | Call 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 steps | describe |
---|---|
Define processor interface | Declare the handler interface and describe the signature of the request processing method. |
Implement the base class according to the interface | In 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 interface | When each handler receives a request, whether to process the request by itself and whether to pass the request along the chain. |
Client link definition | Obtain 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
-
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.
-
Declare the component interface and its series of methods, which are meaningful to both simple and complex elements.
-
Create a leaf node class to represent a simple element. There can be multiple different leaf node classes in the program.
-
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.
-
When implementing component interface methods, remember that the container should leave most of the work to its child elements.
-
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
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
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.