There are six principles and twenty-three design patterns in design patterns. The six principles are single responsibility principle, open and close principle, Richter substitution principle, dependence inversion principle, interface isolation principle, Demeter principle. Twenty-three Design Mode: Singleton pattern, Builder Models, prototype pattern, factory method, abstract factory pattern, strategy pattern, state model, the chain of responsibility pattern, the interpreter, command mode, the observer pattern, memos, iterators, template method, the visitor pattern, mediation patterns, the proxy pattern, combination mode, the adapter pattern, decorative pattern, the flyweight pattern, appearance, bridge . Now let’s introduce the Proxy Pattern.

define

Provide a proxy for other objects to control access to that object. Explanation: Do not want to expose themselves to others, entrust others to help their implementation of certain functions.

The enhancement mentioned on the Internet, in my opinion, is actually to retain the original content, add their own logic (it can also rewrite the parent method implementation, do not delete the super method).

Usage scenarios

When you cannot or do not want to access an object directly, or when an object is inconvenient to access, you can access it indirectly through a proxy object. To implement a proxy, the principal and the proxy need to implement the same interface. The most typical proxy mode is Spring AOP(cut) for example: Xiaoming beat Xiaogang, xiaogang reported xiaoming, at this time, Xiaogang asked a lawyer to deal with the matter on his behalf. If Xiaogang handles it by himself, he needs to submit an application, provide evidence, defend and other litigation procedures. After attorney, Xiaogang entrusted these materials to the lawyer, the lawyer can replace Xiaogang to deal with the matter. In dealing with these processes, lawyers add something of their own (that’s what I call enhancement) in order to succeed.

Proxy mode implementation:

Proxy mode implementation: static proxy and dynamic proxy, dynamic proxy is divided into JDK proxy and Cglib proxy.

Static agent

Static proxies define two implementation classes A and B, both of which implement interface C. The class B constructor passes in A, and THEN B can do something for A.

  • UML diagrams

  • The sample code

  • Litigation Process Interface (Define business interface)

package com.example.pattern.proxy.static
import org.slf4j.Logger
import org.slf4j.LoggerFactory

/** ** procedure */
interface LitigationProcessInterface {
    // File a lawsuit
    fun submitLawsuit(a);
    / / proof
    fun proof(a);
    / / defense
    fun defend(a);

    fun finish(a){
        val logger: Logger = LoggerFactory.getLogger(this: :class.java)
        logger.info("-- -- -- -- - LitigationProcessInterface: : finish the end"); }}Copy the code
  • Materials provided by Xiaogang (proxy 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(a) {
        logger.info("-- -- -- -- -- XiaoGang: : : : : : submit an application for litigation submitLawsuit xiao gang");
    }

    override fun proof(a) {
        logger.info("----- XiaoGang:::::: Proof");
    }

    override fun defend(a) {
        logger.info(----- XiaoGang:::::: Defend XiaoGang); }}Copy the code
  • 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(a) {
        logger.info("----- Lawyer::submitLawsuit1 replace Xiaogang before filing suit")
        // The lawsuit application submitted by Xiaogang
        xiaoGang.submitLawsuit()
        logger.info("----- Lawyer::submitLawsuit2 replaces Xiaogang after the lawsuit application")}override fun proof(a) {
        logger.info("----- Lawyer:: before xiaogang's proof")
        // The evidence submitted by Xiao Gang
        xiaoGang.proof()
        logger.info("----- Lawyer:: after xiaogang's proof")}override fun defend(a) {
        logger.info("----- Lawyer:: Defend1 lawyers before Xiao Gang's defense content")
        // Xiao Gang's defense
        xiaoGang.defend();
        logger.info("----- Lawyer:: Defend2 lawyers after Xiao Gang defends content")}}Copy the code
  • 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()
    }
}
Copy the code
  • The Log information:
12:22:58. [the main] INFO 491 com. Example. The pattern. Proxy. Static. The Lawyer -- -- -- -- -- - Lawyer: : submitLawsuit1 litigation lawyers instead of xiao gang before applying 12:22:58. 496 [the main] INFO com. Example. The pattern. Proxy. Static. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : submit an application for litigation 12:22:58 submitLawsuit xiao gang. 496 (main) INFO com. Example. The pattern. The proxy. Static. The Lawyer -- -- -- -- -- - Lawyer: : submitLawsuit2 lawyers filed instead of xiao gang 12:22:58. After 496 [main] INFO Com. Example. The pattern. The proxy. Static. The Lawyer -- -- -- -- -- - Lawyer: : proof1 Lawyer before xiao gang proof content 12:22:58. [the main] 496 INFO Com. Example. The pattern. The proxy. Static. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : burden of proof xiao gang 12:22:58. [the main] 496 INFO Com. Example. The pattern. The proxy. Static. The Lawyer -- -- -- -- -- - Lawyer: : proof2 Lawyer 12:22:58 after xiao gang proof content. The 496 [main] INFO Com. Example. The pattern. The proxy. Static. The Lawyer -- -- -- -- -- - Lawyer: : defend1 Lawyer before xiao gang defended content 12:22:58. [the main] 496 INFO Com. Example. The pattern. The proxy. Static. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : defend xiao gang defended 12:22:58. 496 (main) INFO Com. Example. The pattern. The proxy. Static. The Lawyer -- -- -- -- -- - Lawyer: : defend2 Lawyer 12:22:58 after xiao gang defended content. The 497 [main] INFO Com. Example. The pattern. The proxy. Static. The Lawyer -- -- -- -- -- - LitigationProcessInterface: : end of finishCopy the code

Static agent while efficiency is quite high, but it is need and business combination, the implementation class needs to implement interface can realize functions of the business, it also limits the need to implement a a proxy object, if there is another proxy objects, you will need to achieve another proxy objects, at this moment, it is not convenient for you to use. Dynamic proxies solve this problem.

The above functions are implemented by using the interface method. In fact, they can also be implemented by using abstract method. It just changes implements to extends.

A dynamic proxy

The static proxy above is compiled from code generated by the programmer or tool, meaning that the compiled file already exists when the code is run. Dynamic proxy is the opposite. It dynamically generates proxy objects through reflection. Java already provides us with a convenient proxy interface, InvocationHandler. Just implement it.

  • The sample code
  • Litigation Process Interface (Define business interface)
package com.example.pattern.proxy.dynamic;
/** ** procedure */
public interface LitigationProcessInterface {
    // File a lawsuit
    void submitLawsuit(a);
    / / proof
    void proof(a);
    / / defense
    void defend(a);
    / / end
    void finish(a);
}
Copy the code
  • Materials provided by Xiaogang (proxy object)
package com.example.pattern.proxy.dynamic;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** ** The content that xiao Gang needs to provide */
public class XiaoGang implements LitigationProcessInterface {
    private Logger logger = LoggerFactory.getLogger( this.getClass());
    public void submitLawsuit(a) {
        logger.info("-- -- -- -- -- XiaoGang: : : : : : submit an application for litigation submitLawsuit xiao gang");
    }

    public void proof(a) {
        logger.info("----- XiaoGang:::::: Proof");
    }

    public void defend(a) {
        logger.info(----- XiaoGang:::::: Defend XiaoGang);
    }

    public void finish(a) {
        logger.info("----- XiaoGang:::::: Finish"); }}Copy the code
  • Proxy objects
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;
    }

    /** * reflection **@paramProxy Proxy instance *@param* method method@paramArgs method parameter *@returnResults *@throwsThrowable exception * /
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        return method.invoke(this.object, args); }}Copy the code
  • implementation
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 proxied object
        ClassLoader xiaoGangClassLoader = xiaoGang.getClass().getClassLoader();
        // create a proxy lawyer dynamically
        LitigationProcessInterface lawyer = (LitigationProcessInterface) Proxy.newProxyInstance(xiaoGangClassLoader, newClass[]{LitigationProcessInterface.class}, dynamicProxy); lawyer.submitLawsuit(); lawyer.proof(); lawyer.defend(); lawyer.finish(); }}Copy the code
  • Log
13:23:01. [the main] INFO 047 com. Example. The pattern. The proxy. Dynamic. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : submitLawsuit xiao gang submit an application for action 13:23:01. [the main] INFO 050 com. Example. The pattern. The proxy. Dynamic. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : proof 13:23:01 want xiao gang. 050 (main) INFO com. Example. The pattern. The proxy. Dynamic. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : defend xiao gang defended 13:23:01. [the main] 050 INFO Com. Example. The pattern. The proxy. Dynamic. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : end of finishCopy the code

The above code and static agent like very much, but when adding another proxy objects, static agents need to implement a class (LitigationProcessInterface), the dynamic proxy is don’t need to, as long as the instance of agent again.

Defining a DynamicProxy object is also limited. It cannot add additional things (enhancements). If additional things need to be added, each object needs to be redefined, just like static proxies.

We can also simply new an InvocationHandler object to add extra stuff.

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 replace Xiaogang before filing suit");
                    method.invoke(xiaoGang, args);
                    logger.info("----- Lawyer::submitLawsuit2 replaces Xiaogang after the lawsuit application");

                } else if ("proof".equals(method.getName())){
                    logger.info("----- Lawyer:: before xiaogang's proof");
                    method.invoke(xiaoGang, args);
                    logger.info("----- Lawyer:: after xiaogang's proof");
                } else if ("defend".equals(method.getName())){
                    logger.info("----- Lawyer:: Defend1 lawyers before Xiao Gang's defense content");
                    method.invoke(xiaoGang, args);
                    logger.info("----- Lawyer:: Defend2 lawyers after Xiao Gang defends content");
                } else if ("finish".equals(method.getName())){
                    logger.info("----- Lawyer:: Finish1 before the end");
                    method.invoke(xiaoGang, args);
                    logger.info("----- Lawyer::finish2 after end");
                }
                return null; }};// Get the ClassLoader of the proxied object
        ClassLoader xiaoGangClassLoader = xiaoGang.getClass().getClassLoader();
        // create a proxy lawyer dynamically
        LitigationProcessInterface lawyer = (LitigationProcessInterface) Proxy.newProxyInstance(xiaoGangClassLoader, newClass[]{LitigationProcessInterface.class}, invocationHandler); lawyer.submitLawsuit(); lawyer.proof(); lawyer.defend(); lawyer.finish(); }}Copy the code
  • Log
13:50:04. [the main] INFO 564 com. Example. The pattern. Proxy. Dynamic. The Client -- -- -- -- -- - Lawyer: : submitLawsuit1 litigation lawyers instead of xiao gang before applying 13:50:04. [the main] INFO 567 com. Example. The pattern. The proxy. Dynamic. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : submitLawsuit xiao gang submit an application for action 13:50:04. [the main] INFO 567 com. Example. The pattern. Proxy. Dynamic. The Client -- -- -- -- -- - Lawyer: : submitLawsuit2 litigation lawyers instead of xiao gang after application 13:50:04. [the main] INFO 567 com. Example. The pattern. Proxy. Dynamic. The Client -- -- -- -- -- - Lawyer: : proof1 Lawyer 13:50:04 before xiao gang proof content. 567 (main) INFO com. Example. The pattern. The proxy. Dynamic. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : burden of proof xiao gang 13:50:04. [the main] 567 INFO Com. Example. The pattern. The proxy. Dynamic. The Client -- -- -- -- -- - Lawyer: : proof2 Lawyer 13:50:04 after xiao gang proof content. The 567 [main] INFO Com. Example. The pattern. The proxy. Dynamic. The Client -- -- -- -- -- - Lawyer: : defend1 Lawyer before xiao gang defended content 13:50:04. [the main] 567 INFO Com. Example. The pattern. The proxy. Dynamic. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : defend xiao gang defended 13:50:04. 567 (main) INFO Com. Example. The pattern. The proxy. Dynamic. The Client -- -- -- -- -- - Lawyer: : defend2 Lawyer 13:50:04 after xiao gang defended content. The 567 [main] INFO Com. Example. The pattern. The proxy. Dynamic. The Client -- -- -- -- -- - Lawyer: : finish1 13:50:04. Before the end of 567. [the main] INFO Com. Example. The pattern. The proxy. Dynamic. XiaoGang -- -- -- -- -- - XiaoGang: : : : : : finish end 13:50:04. [the main] 567 INFO Com. Example. The pattern. The proxy. Dynamic. The Client -- -- -- -- -- - Lawyer: : after the finish2Copy the code

This type of Log is very similar to the first one, but it does not need to create multiple proxy objects.

Additional agent

Both of these agents require specific interfaces to implement proxy functionality, or enhancements. The Cglib package provided by Spring simplifies the implementation interface so that a proxy can be implemented as a single object.

  • Define the proxied object
package com.example.pattern.proxy.enhancer;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/** ** The content that xiao Gang needs to provide */
public class XiaoGang {
    private Logger logger = LoggerFactory.getLogger(this.getClass());

    public void submitLawsuit(a) {
        logger.info("-- -- -- -- -- XiaoGang: : : : : : submit an application for litigation submitLawsuit xiao gang");
    }

    public void proof(a) {
        logger.info("----- XiaoGang:::::: Proof");
    }

    public void defend(a) {
        logger.info(----- XiaoGang:::::: Defend XiaoGang);
    }

    public void finish(a) {
        logger.info("----- XiaoGang:::::: Finish"); }}Copy the code
  • Proxy objects
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 begins");
        // Execute the target object's method
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("End of ----- ProxyFactory:::::: Intercept");
        returnresult; }}Copy the code
  • implementation
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();
        // Inherits the proxied class
        enhancer.setSuperclass(XiaoGang.class);
        // Set the 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 the proxy object
        XiaoGang xiaoGang = (XiaoGang) enhancer.create();
        // Methods in the proxy class will be intercepted by the method interceptor we implementedxiaoGang.submitLawsuit(); xiaoGang.proof(); xiaoGang.defend(); xiaoGang.finish(); }}Copy the code
  • LOG
----- ProxyFactory:::::: Intercept began 14:22:11. 317. [the main] INFO com. The example. The pattern. The proxy. Enhancer. XiaoGang $$EnhancerByCGLIB $$4 d9ceeba -- -- -- -- -- - XiaoGang: : : : : : submit an application for action -- -- -- -- -- submitLawsuit xiao gang ProxyFactory: : : : : : to intercept the end -- -- -- -- -- ProxyFactory: : : : : : Intercept began 14:22:11. 320. [the main] INFO com. The example. The pattern. The proxy. Enhancer. XiaoGang $$EnhancerByCGLIB $$4 d9ceeba -- -- -- -- -- - XiaoGang: : : : : : -- -- -- -- -- of proof proof xiao gang ProxyFactory: : : : : : to intercept the end -- -- -- -- -- ProxyFactory: : : : : : Intercept began 14:22:11. 320. [the main] INFO com. The example. The pattern. The proxy. Enhancer. XiaoGang $$EnhancerByCGLIB $$4 d9ceeba -- -- -- -- -- - XiaoGang: : : : : : defense -- -- -- -- -- defend xiao gang ProxyFactory: : : : : : intercept end -- -- -- -- -- ProxyFactory: : : : : : Intercept began 14:22:11. 320. [the main] INFO com. The example. The pattern. The proxy. Enhancer. XiaoGang $$EnhancerByCGLIB $$4 d9ceeba -- -- -- -- -- - XiaoGang:::::: Finish ----- ProxyFactory:::::: Intercept EndCopy the code

This proxy is simpler and more convenient than dynamic proxy. If you want to extend the method, you can implement it directly by new MethodInterceptor, similar to the dynamic proxy New InvocationHandler.

conclusion

Learning to use design patterns can make our code more beautiful. A lot of times in our programming, we write code that uses design patterns, but it’s just not clear. After checking blogs and books, I have a preliminary understanding of the agent pattern. If the writing is not good, please correct the majority of netizens. Demo address: github.com/wdmxzf/java…