Creation: singleton, prototype, factory
Structural: Agent mode, decorator mode, adapter mode, facade mode
Behavior: Observer mode, template mode, policy mode, responsibility chain mode
Chain of Responsibility model
Concept: A responsibility chain is a list that records the beginning and end of a linked list. The record header is used for queueing messages and the record tail is used for adding processors.
Function: reuse and extension, we can use the chain of responsibility to provide the framework extension point, let users without modifying the framework source code, based on the extension to customize their own needs. It decouples the sending and receiving of a message, giving each node in the chain of responsibility the opportunity to process the message.
Usage:
(1) The use of linked list, can be processed on the request directly intercept processing and return, can not be passed down to the subsequent processor to process; With arrays, each request is processed by all the processors.
② Use the template method pattern to separate the movement of messages along the responsibility chain from the business logic processing of messages. The logic that calls the next responsibility chain node is put into the abstract superclass, and the concrete processor class implements its own doHandle() method.
(The Socket project uses the responsibility chain model to achieve single chat and group chat functions.)
Adapter mode
The adaptor pattern is used for adaptation. It is equivalent to converting two incompatible interfaces into a compatible interface whose implementation class can also accommodate multiple incompatible interface methods.
Application Scenarios:
(1) The interface provided by the external system is encapsulated twice, and the external method is enhanced to achieve better design (the adapter realizes the reconstruction interface inherits the external interface, and the adapter is equivalent to the implementation class, providing the implementation method for the reconstruction interface)
② The implementation of each function may need to implement multiple interfaces according to different choices, so we can provide an adapter for multiple interfaces to provide a unified interface definition, according to different conditions of self-adaptation of different implementations, is essentially the use of polymorphisms to achieve code reuse logic. Compatible with interfaces of earlier versions, avoiding direct deletion.
Specific scene:
① My SocketChannelAdapter ADAPTS to different IOproviders
Spring Slf4j logging framework. It provides a unified interface definition and adapters for different logging frameworks, and then re-encapsulates the interfaces of different logging frameworks into a unified Slf4j interface adapter. All we need to do is import the appropriate SDK, and Spring will determine which logging technology dependencies the JVM can load to determine which logging technology can be used. Slf4j also provides a reverse adapter that ADAPTS from Slf4j to other logging frameworks, so we can go from JCL to Slf4j to Logback. (Log4j2 logging is preferred in Spring, Slf4j logging framework is used if not)
Template method patterns and callbacks
Template method pattern: the same business logic is removed to the parent class, for different business logic, through the abstract method to force the subclass to rewrite, code reuse and framework template based code extension (removed from the framework extension point for users to rewrite).
Callback: Class A registers the function with class B, and then class A calls another function of class B, which triggers the callback function of class A and returns the result to class A. This is the callback. That is, the callback is also reusing class B code logic to trigger custom callback functions.
Template method patterns are based on inheritance and callbacks are based on composition. Java supports only single inheritance, and if you put all template methods into a parent class, you’ll need to override abstract methods that aren’t used by subclasses. So callbacks are more flexible and convenient,
(The ConnectorHandlerChain class is the template method pattern.)
Singleton mode:
The singleton pattern ensures that a class creates only one instance and provides its global access point.
Hungry singleton: during the class loading stage, a chunk of memory is opened in the heap, instantiated singleton objects and put into the memory, so as to ensure the uniqueness of instances in the case of multiple threads. It is loaded at initialization and fetched directly at runtime with very high performance; However, these singleton objects occupy heap memory from the class loading stage onwards and waste space if not used.
Lazy singleton: It uses lazy loading so that instances are loaded into memory only when the system uses the class. If alone does not guarantee thread-safety, so we use synchronized locks to decorate methods. However, the synchronization lock will produce competition, which will bring system performance cost, so we do if judgment before the synchronization lock is not added, to avoid the lock contention cost when the lock is occupied, so as to reduce the resource competition of the synchronization lock. With such double-check, even in multi-threaded cases if multiple threads enter the first if condition at the same time, they can only create one instance. However, there are instructions reordering problems. If you allocate memory to an object and assign instance to a member variable, but the object has not executed the constructor’s code logic, then another thread has just allocated to the CPU, and the execution determines that the object is not empty, so it returns to use. However, the member variable has not been initialized at this point, which may cause an exception. Therefore, we need to use the volatile keyword to modify the object to prevent local instruction reordering.
public class Singleton{
public volatile static A instance = null;
public A getInstance(){
if(instance==null) {synchronized(instance){
if(instance==null) instance = newA(); }}return instance;
}
}
public class LazySingleton{
private static LazySingleton ls = null;
public synchronized static LazySingleton getInstance(){
if(lazySingleton==null){
lazySingleton = new LazySingleton();
}
}
}
public class ehanshiSingleton{
private static ESingleton es = new Singleton();
public static ESingleton getES(){
returnes; }} You can use enumerations to prevent reflectionCopy the code
Of course, we use the static inner class directly to initialize the member variables. The static inner class is loaded only once, so we put the instantiation of the singleton object into the static variable initialization of the static inner class to achieve singleton uniqueness.
Note: The core of the guarantee singleton is the guarantee through external shared storage. All the above mentioned is to ensure that the object is unique in a single process, and the process and process are independent, each occupies different address space, and then ensure the uniqueness of the object in the process. If you want to make objects unique in a thread, you use ThreadLocal, the thread’s external shared memory. To ensure object uniqueness between processes, external shared storage such as files and disks is required.
Enumeration prevents reflection from breaking the singleton pattern
Enumerations are also Java classes, and when we decompile them we can see that they are actually abstract classes that cannot be instantiated externally. When reflecting newInstance to create an object of an enumerated class, it checks to see if the class is decorated with an ENUM and throws an exception if it is
And the enumeration class is constructed in a static block, which ensures thread-safety during JVM class loading.
Observer mode:
Also known as publishave-subscribe, we can define a one-to-many dependency between objects. When the state of one object changes, all other dependent objects are notified, which decouples the dependent objects. And if only observer blocking wait for a notice, belong to a synchronized block is implemented, the effect is not very good, so we can use the asynchronous non-blocking implementation approach, to reduce the response time: we can put the need to notify the incident in the asynchronous thread pool, through asynchronous thread to notify observer, then the observer without blocking the wait for a notice
The strategy pattern
The policy pattern essentially decouples the creation and use of objects. A policy pattern contains a set of policies, which are usually determined by type, so we can abstract the logic to create policies based on type into a factory class or Map. We don’t have to pay attention to the various policies when we use them. We just need to pass in the type of response and the policy factory automatically creates the object for us (the policy Map automatically returns the corresponding functional interface) to perform the response business logic.
Decorator mode
The decorator pattern is primarily used to add enhancements to primitive classes, and it solves the problem of overly complex inheritance relationships by substituting composition for multiple inheritance.
Factory mode:
Simple Factory pattern: The simple Factory pattern is the simple factory pattern class that creates objects by taking the code blocks that are used to create objects and encapsulating them into functions, and then separating them into a separate class that only creates objects. The simple factory pattern is designed to make the responsibilities of a class more simple and the functionality clearer. However, the creation of an object can involve multiple Ifs. If we want to remove the IFs from a simple factory, we need to use the factory method pattern.
Factory method pattern: We maintain an interface method that creates objects in the interface, and then, taking advantage of the polymorphic nature, let each implementation class self-implement object creation in this method. This is equivalent to breaking down complex conditions (multiple Ifs) in a simple factory into subclass factories. But this is obviously a problem, because it creates a strong coupling between the object creation and the subclass factory, just like creating the object directly, except that the if condition is wrapped around it. So we can also create a simple factory for these subclass factories, which is the factory for creating the factory, using a Map store with key as the if condition and value as the factory subclass, in combination with the policy pattern. So when we expand the factory, we simply add kv key-value pairs to the Map of the simple factory.
Abstract factory pattern: It is to combine the interfaces abstracted from the factory method pattern and put part of the associated object creation logic into one interface, so that one factory can be responsible for creating multiple objects of different types and avoid creating too many factory classes.
Design patterns in Spring
BeanFactory Factory pattern, HandlerAdapter adapter pattern, Bean singleton pattern, AOP proxy pattern, Template Template method pattern, ApplicationListener observer pattern.
Design patterns in the JDK
Factory mode: Integer.valueof (), class.forname (GZFF /name), and java.sql/Connection can create different statements.
Prototype pattern: deep copy, shallow copy
Adapter pattern: InputStreamReader(InputStream) Transforms a stream.
Decorator pattern: Collections. SynchronizedList (list)
Proxy mode: Dynamic proxy
Policy mode: The four rejection policies of ThreadPoolExecutor