There are six principles and twenty-three design patterns in the design pattern.
The six principles are: single responsibility principle, opening and closing principle, Richter substitution principle, dependency inversion principle, interface isolation principle and Dimitri principle.
Twenty three design patterns: Singleton pattern, Builder pattern, prototype pattern, factory method pattern, abstract factory pattern, policy pattern, state pattern, responsibility chain pattern, Interpreter pattern, command pattern, observer pattern, memo pattern, iterator pattern, template method pattern, visitor pattern, mediation pattern, agent pattern, composition pattern, adapter pattern Decoration mode, element sharing mode, appearance mode and bridging mode.
Now let's introduce the Proxy Pattern.
definition
Provide a proxy to other objects to control access to this object.
Explanation: I just don't want to expose myself to others and entrust others to help me realize some functions.
In my opinion, the enhancement on the Internet is actually to retain the original content and add their own logic (he can also rewrite the parent method implementation without deleting the super method).
Usage scenario
When an object cannot or does not want to be accessed directly, or an object is inconvenient to access, it can be accessed indirectly through a proxy object. To implement an agent, you need to implement the same interface as the delegate and the agent. The most typical proxy pattern is Spring's AOP (aspect)
For example, Xiaoming beat Xiaogang and Xiaogang sued Xiaoming. At this time, Xiaogang asked a lawyer to handle the matter on his behalf. If Xiaogang handles it by himself, he needs to submit an application, provide evidence, defend and other litigation processes. After entrusting a lawyer, Xiao Gang entrusts these materials to a lawyer, and the lawyer can handle the matter instead of Xiao Gang. In dealing with these processes, lawyers have added some things of their own for the success of litigation (this is what I think [enhancement]).
Proxy mode implementation:
Implementation mode of agent mode: static agent and dynamic agent, and dynamic agent is divided into jdk agent and Cglib agent.
Static proxy
Static proxy is to define two implementation classes a and B, both of which implement interface C. class B constructor passes in a, and then B can do something instead of A.
-
UML diagram
-
Sample code
-
Litigation process interface (define business interface)
package com.example.pattern.proxy.static import org.slf4j.Logger import org.slf4j.LoggerFactory /** * Litigation process */ interface LitigationProcessInterface { // Filing a lawsuit fun submitLawsuit(); // Proof fun proof(); // defend fun defend(); fun finish(){ val logger: Logger = LoggerFactory.getLogger(this::class.java) logger.info("----- LitigationProcessInterface::finish end"); } }
- Materials provided by Xiao Gang (represented object)
package com.example.pattern.proxy.static import org.slf4j.Logger import org.slf4j.LoggerFactory class XiaoGang : LitigationProcessInterface { private val logger: Logger = LoggerFactory.getLogger(this::class.java) override fun submitLawsuit() { logger.info("----- XiaoGang::::::submitLawsuit Xiao Gang filed a lawsuit"); } override fun proof() { logger.info("----- XiaoGang::::::proof Xiao Gang adduces evidence"); } override fun defend() { logger.info("----- XiaoGang::::::defend Xiaogang defense"); } }
- Attorney (agent)
package com.example.pattern.proxy.static import org.slf4j.Logger import org.slf4j.LoggerFactory /** * lawyer */ class Lawyer(private val xiaoGang: XiaoGang) : LitigationProcessInterface { private val logger: Logger = LoggerFactory.getLogger(this::class.java) override fun submitLawsuit() { logger.info("----- Lawyer::submitLawsuit1 Before the lawyer replaces Xiao Gang's lawsuit application") // Application submitted by Xiao Gang xiaoGang.submitLawsuit() logger.info("----- Lawyer::submitLawsuit2 After the lawyer applied for the lawsuit instead of Xiao Gang") } override fun proof() { logger.info("----- Lawyer::proof1 The lawyer before Xiao Gang's proof") // Evidence submitted by Xiao Gang xiaoGang.proof() logger.info("----- Lawyer::proof2 After Xiao Gang provided evidence") } override fun defend() { logger.info("----- Lawyer::defend1 The lawyer is in front of Xiaogang's defense") // Xiao Gang's defense xiaoGang.defend(); logger.info("----- Lawyer::defend2 After Xiao Gang's defense") } }
- Process implementation (Implementation)
package com.example.pattern.proxy.static object Client { @JvmStatic fun main(args: Array<String>) { val xiaoGang:LitigationProcessInterface = XiaoGang(); val lawyer = Lawyer(xiaoGang as XiaoGang) lawyer.submitLawsuit() lawyer.proof() lawyer.defend() lawyer.finish() } }
- Log information:
12:22:58.491 [main] INFO com.example.pattern.proxy.static.Lawyer - ----- Lawyer::submitLawsuit1 Before the lawyer replaces Xiao Gang's lawsuit application 12:22:58.496 [main] INFO com.example.pattern.proxy.static.XiaoGang - ----- XiaoGang::::::submitLawsuit Xiao Gang filed a lawsuit 12:22:58.496 [main] INFO com.example.pattern.proxy.static.Lawyer - ----- Lawyer::submitLawsuit2 After the lawyer applied for the lawsuit instead of Xiao Gang 12:22:58.496 [main] INFO com.example.pattern.proxy.static.Lawyer - ----- Lawyer::proof1 The lawyer before Xiao Gang's proof 12:22:58.496 [main] INFO com.example.pattern.proxy.static.XiaoGang - ----- XiaoGang::::::proof Xiao Gang adduces evidence 12:22:58.496 [main] INFO com.example.pattern.proxy.static.Lawyer - ----- Lawyer::proof2 After Xiao Gang provided evidence 12:22:58.496 [main] INFO com.example.pattern.proxy.static.Lawyer - ----- Lawyer::defend1 The lawyer is in front of Xiaogang's defense 12:22:58.496 [main] INFO com.example.pattern.proxy.static.XiaoGang - ----- XiaoGang::::::defend Xiaogang defense 12:22:58.496 [main] INFO com.example.pattern.proxy.static.Lawyer - ----- Lawyer::defend2 After Xiao Gang's defense 12:22:58.497 [main] INFO com.example.pattern.proxy.static.Lawyer - ----- LitigationProcessInterface::finish end
Although the static proxy is very efficient, it needs to be used in combination with the business. The implementation classes need to implement the business interface to realize the function. This also limits that a proxy object needs to be implemented once. If there is another proxy object, it also needs to implement another proxy object. At this time, it is not very convenient to use. Then dynamic agent solves this problem.
The above functions are implemented by using interface. In fact, they can also be implemented by using abstract. It's just that implements has been changed to extends
Dynamic agent
The above static agent is compiled by the code generated by the programmer or tool, that is, the compiled file already exists when the code is run. On the contrary, dynamic proxy dynamically generates proxy objects through reflection mechanism.
Java has provided us with a convenient proxy interface InvocationHandler. Just implement it.
- Sample code
- Litigation process interface (define business interface)
package com.example.pattern.proxy.dynamic; /** * Litigation process */ public interface LitigationProcessInterface { // Filing a lawsuit void submitLawsuit(); // Proof void proof(); // defend void defend(); // end void finish(); }
- Materials provided by Xiao Gang (represented object)
package com.example.pattern.proxy.dynamic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * What Xiaogang needs to provide */ public class XiaoGang implements LitigationProcessInterface { private Logger logger = LoggerFactory.getLogger( this.getClass()); public void submitLawsuit() { logger.info("----- XiaoGang::::::submitLawsuit Xiao Gang filed a lawsuit"); } public void proof() { logger.info("----- XiaoGang::::::proof Xiao Gang adduces evidence"); } public void defend() { logger.info("----- XiaoGang::::::defend Xiaogang defense"); } public void finish() { logger.info("----- XiaoGang::::::finish end"); } }
- Proxy object
package com.example.pattern.proxy.dynamic; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * proxy class */ public class DynamicProxy implements InvocationHandler { private Object object; public DynamicProxy(Object o) { this.object = o; } /** * reflex * * @param proxy Proxy instance * @param method method * @param args Method parameters * @return result * @throws Throwable abnormal */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(this.object, args); } }
- realization
package com.example.pattern.proxy.dynamic; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { LitigationProcessInterface xiaoGang = new XiaoGang(); DynamicProxy dynamicProxy= new DynamicProxy(xiaoGang); //Get the ClassLoader of the proxy object Xiao Gang ClassLoader xiaoGangClassLoader = xiaoGang.getClass().getClassLoader(); // Dynamically construct an attorney LitigationProcessInterface lawyer = (LitigationProcessInterface) Proxy.newProxyInstance(xiaoGangClassLoader, new Class[]{LitigationProcessInterface.class}, dynamicProxy); lawyer.submitLawsuit(); lawyer.proof(); lawyer.defend(); lawyer.finish(); } }
- Log
13:23:01.047 [main] INFO com.example.pattern.proxy.dynamic.XiaoGang - ----- XiaoGang::::::submitLawsuit Xiao Gang filed a lawsuit 13:23:01.050 [main] INFO com.example.pattern.proxy.dynamic.XiaoGang - ----- XiaoGang::::::proof Xiao Gang adduces evidence 13:23:01.050 [main] INFO com.example.pattern.proxy.dynamic.XiaoGang - ----- XiaoGang::::::defend Xiaogang defense 13:23:01.050 [main] INFO com.example.pattern.proxy.dynamic.XiaoGang - ----- XiaoGang::::::finish end
The above code is very similar to the static proxy, but when another proxy object is added, the static proxy needs to re implement a class (limitationprocessinterface), while the dynamic proxy does not need to. Just use the proxy under the instance.
In fact, defining a proxy object DynamicProxy alone is also limited. It cannot add additional things (that is, the so-called enhancement). If additional things need to be added, each proxy object needs to be redefined, which is no different from static proxy.
Then we can also directly create an InvocationHandler object, so that we can add additional things.
package com.example.pattern.proxy.dynamic; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class Client { public static void main(String[] args) { final Logger logger = LoggerFactory.getLogger( Client.class); final LitigationProcessInterface xiaoGang = new XiaoGang(); // Method 2 InvocationHandler invocationHandler = new InvocationHandler() { public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { if ("submitLawsuit".equals(method.getName())){ logger.info("----- Lawyer::submitLawsuit1 Before the lawyer replaces Xiao Gang's lawsuit application"); method.invoke(xiaoGang, args); logger.info("----- Lawyer::submitLawsuit2 After the lawyer applied for the lawsuit instead of Xiao Gang"); } else if ("proof".equals(method.getName())){ logger.info("----- Lawyer::proof1 The lawyer before Xiao Gang's proof"); method.invoke(xiaoGang, args); logger.info("----- Lawyer::proof2 After Xiao Gang provided evidence"); } else if ("defend".equals(method.getName())){ logger.info("----- Lawyer::defend1 The lawyer is in front of Xiaogang's defense"); method.invoke(xiaoGang, args); logger.info("----- Lawyer::defend2 After Xiao Gang's defense"); } else if ("finish".equals(method.getName())){ logger.info("----- Lawyer::finish1 Before the end"); method.invoke(xiaoGang, args); logger.info("----- Lawyer::finish2 After the end"); } return null; } }; //Get the ClassLoader of the proxy object Xiao Gang ClassLoader xiaoGangClassLoader = xiaoGang.getClass().getClassLoader(); // Dynamically construct an attorney LitigationProcessInterface lawyer = (LitigationProcessInterface) Proxy.newProxyInstance(xiaoGangClassLoader, new Class[]{LitigationProcessInterface.class}, invocationHandler); lawyer.submitLawsuit(); lawyer.proof(); lawyer.defend(); lawyer.finish(); } }
- Log
13:50:04.564 [main] INFO com.example.pattern.proxy.dynamic.Client - ----- Lawyer::submitLawsuit1 Before the lawyer replaces Xiao Gang's lawsuit application 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.XiaoGang - ----- XiaoGang::::::submitLawsuit Xiao Gang filed a lawsuit 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.Client - ----- Lawyer::submitLawsuit2 After the lawyer applied for the lawsuit instead of Xiao Gang 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.Client - ----- Lawyer::proof1 The lawyer before Xiao Gang's proof 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.XiaoGang - ----- XiaoGang::::::proof Xiao Gang adduces evidence 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.Client - ----- Lawyer::proof2 After Xiao Gang provided evidence 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.Client - ----- Lawyer::defend1 The lawyer is in front of Xiaogang's defense 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.XiaoGang - ----- XiaoGang::::::defend Xiaogang defense 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.Client - ----- Lawyer::defend2 After Xiao Gang's defense 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.Client - ----- Lawyer::finish1 Before the end 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.XiaoGang - ----- XiaoGang::::::finish end 13:50:04.567 [main] INFO com.example.pattern.proxy.dynamic.Client - ----- Lawyer::finish2 After the end
Is this kind of Log similar to the first one, and it no longer needs to create multiple proxy objects.
Cglib agent
Both of the above two agents need to implement specific interfaces to realize the agent function or enhance the function. The Cglib package provided by Spring simplifies the implementation interface, and the proxy can be implemented as long as it is a separate object.
- Define proxied objects
package com.example.pattern.proxy.enhancer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * What Xiaogang needs to provide */ public class XiaoGang { private Logger logger = LoggerFactory.getLogger(this.getClass()); public void submitLawsuit() { logger.info("----- XiaoGang::::::submitLawsuit Xiao Gang filed a lawsuit"); } public void proof() { logger.info("----- XiaoGang::::::proof Xiao Gang adduces evidence"); } public void defend() { logger.info("----- XiaoGang::::::defend Xiaogang defense"); } public void finish() { logger.info("----- XiaoGang::::::finish end"); } }
- Proxy object
package com.example.pattern.proxy.enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; public class ProxyInterceptor implements MethodInterceptor { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("----- ProxyFactory:::::: intercept start "); //Method of executing target object Object result = methodProxy.invokeSuper(o, objects); System.out.println("----- ProxyFactory:::::: intercept end "); return result; } }
- realization
package com.example.pattern.proxy.enhancer; import org.springframework.cglib.proxy.Enhancer; public class Client { public static void main(String[] args) { Enhancer enhancer = new Enhancer(); //Inherit the proxied class enhancer.setSuperclass(XiaoGang.class); //Set callback enhancer.setCallback(new ProxyInterceptor()); // enhancer.setCallback(new MethodInterceptor() { // public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { // //Can be enhanced // return null; // } // }); // enhancer.setCallbackFilter(new CallbackFilter() { // public int accept(Method method) { // return 0; // } // }); //Set proxy class object XiaoGang xiaoGang = (XiaoGang) enhancer.create(); //When calling the method in the proxy class, it will be intercepted by the method interceptor we implemented xiaoGang.submitLawsuit(); xiaoGang.proof(); xiaoGang.defend(); xiaoGang.finish(); } }
- LOG
----- ProxyFactory:::::: intercept start 14:22:11.317 [main] INFO com.example.pattern.proxy.enhancer.XiaoGang$$EnhancerByCGLIB$$4d9ceeba - ----- XiaoGang::::::submitLawsuit Xiao Gang filed a lawsuit ----- ProxyFactory:::::: intercept end ----- ProxyFactory:::::: intercept start 14:22:11.320 [main] INFO com.example.pattern.proxy.enhancer.XiaoGang$$EnhancerByCGLIB$$4d9ceeba - ----- XiaoGang::::::proof Xiao Gang adduces evidence ----- ProxyFactory:::::: intercept end ----- ProxyFactory:::::: intercept start 14:22:11.320 [main] INFO com.example.pattern.proxy.enhancer.XiaoGang$$EnhancerByCGLIB$$4d9ceeba - ----- XiaoGang::::::defend Xiaogang defense ----- ProxyFactory:::::: intercept end ----- ProxyFactory:::::: intercept start 14:22:11.320 [main] INFO com.example.pattern.proxy.enhancer.XiaoGang$$EnhancerByCGLIB$$4d9ceeba - ----- XiaoGang::::::finish end ----- ProxyFactory:::::: intercept end
This kind of agent is simpler and more convenient than dynamic agent. If you want to extend the method, you can directly implement the new MethodInterceptor, which is similar to the dynamic agent new InvocationHandler.
summary
Learning to use design patterns can make our code more beautiful. In our programming process, we often use design patterns in the code we write, but it's not clear.
After checking blogs and books, I have a preliminary understanding of the agent model. If the writing is not good, please correct it.
demo address: https://github.com/wdmxzf/java-example/tree/pattern