当前位置:网站首页>Which is the best agency mode or decoration mode

Which is the best agency mode or decoration mode

2022-06-22 06:37:00 Cappuccino Haichen

Catalog

One 、 Preface

Two 、JDK Dynamic proxy model

1、 Components and methods used in development

2、 It's already said , The proxy class delegates to InvocationHandler Interface implementation classes to handle tasks , Task logic must go through invoke() Method , Let's see what it looks like in the source code :

3、 experimental data

3.1、Subject Interface

3.2、Subject Implementation class of interface RealSubject

3.3、InvocationHandler Implementation class of ,Cache Call processor

3.4、 Test class

3.5、 Console print results :

4、 increase InvocationHandler An implementation class SyCache

5、 Modify and supplement JDKProxyTest

6、 summary

3、 ... and 、 Decoration mode

1、 What problems can decoration pattern solve

2、 From class diagram to decoration pattern

2.1、Component Component interface

2.2、CorrectComponent Specific component implementation class

2.3、CorrectDecorator Specific decorators 1

2.4、CorrectDecorator2 Specific decorators 2

2.5、Condition Auxiliary condition class

2.6、DecoratorWrapper Decorator packaging class

2.7、 Test class

2.8、 test result ​ edit  

2.9、 summary

Four 、 What's the difference between dynamic proxy and decoration mode


One 、 Preface

    Design patterns , As a programmer, I still need to master some . As small as software intermediate designer exam 、 interview 、 Read the source code of the framework , Big to daily development 、 The system architecture will be encountered . And the author is also back in the period of College , I have a little knowledge of design patterns .

    JDK A dynamic proxy , Its role in the world of source code is particularly important , Such as MyBatis Log module of 、binding Module etc. ,Spring Of AOP etc. . In daily development , You can also capture its shadow . An important goal of using proxies is to control access to the proxied classes , You can do some prefixes in the proxy class / Post processing , Such as : cache journal Business jurisdiction wait . Use JDK The premise of dynamic proxy is : The proxied class must be an interface or its implementation class . If the proxy class is not an interface or an interface implementation class , And you want to use dynamic proxies , Consider using CGLIBJavassist technology . This is a hard skill , well Java The engineer 、 The knowledge that architects must have .

    Decoration mode , You can dynamically add functions to objects , This is a classic introduction . It may not be often encountered in daily development , But you can still capture it in the source code .

   JDK In fact, there have always been many disputes between dynamic agent mode and decoration mode , Many scholars believe that there is no big difference between them , Even call them the same thing . Today, let's discuss their differences from an experimental point of view , As Grandpa Deng Xiaoping said :“ Practice is the only criterion for testing truth ”.

Two 、JDK Dynamic proxy model

Why are there so many proxy patterns , This is just one of them . Because in daily development , Common is to use JDK A dynamic proxy . Interested readers can study other types of agency models by themselves .

1、 Components and methods used in development

Development JDK The dynamic agent component is InvocationHandler Interface as well as Proxy class , Their responsibilities are as follows :

class   Class
Proxy class   Responsible for generating proxy class And associated with Call processor (InvocationHandler Implementation class of interface )
InvocationHandler Interface Responsible for handling the logic of the agent , Such as : cache journal Business jurisdiction wait

1.1、 describe

Proxy The generated proxy class does not handle logic , Abstract and very real. You don't even see how to write logic in the proxy class body , But it will be delegated to Call processor Of invoke() Method processing logic , That's why there are more InvocationHandler Interface and its implementation class . We all know , To call a class's Non static methods , Generally, you have to go through it example To call methods . Easy to handle ,Proxy The generated proxy class does not handle logic , Which is delegated to the calling processor invoke() Method treatment , Then call the method that calls the processor , You must at least get an instance of it . so Proxy Of newProxyInstance() Method ( This method is often used in development ) You have to call the processor example Incoming . Let's take a look at the parameters of this method in the source code :

Source code :


    /**
     * Returns an instance of a proxy class for the specified interfaces
     * that dispatches method invocations to the specified invocation
     * handler.
     * @param   loader the class loader to define the proxy class
     * @param   interfaces the list of interfaces for the proxy class
     *          to implement
     * @param   h the invocation handler to dispatch method invocations to
     * @return  a proxy instance with the specified invocation handler of a
     *          proxy class that is defined by the specified class loader
     *          and that implements the specified interfaces
     */
    @CallerSensitive
    public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException
    {

Method is responsible for creating proxy class instances , And the proxy class is associated with the calling processor that takes over processing the logical task .

loader: Class loader , Responsible for loading proxy classes .

interfaces: An array type , Indicates that an array of interface objects is provided , Then the proxy class implements all the methods of these interfaces and can call .

h:InvocationHandler Interface type , The proxy class will pass through InvocationHandler Implement an instance of a class to call invoke() Method processing logic .

2、 It's already said , The proxy class delegates to InvocationHandler Interface implementation classes to handle tasks , Task logic must go through invoke() Method , Let's see what it looks like in the source code :

/**
     * Processes a method invocation on a proxy instance and returns
     * the result.  This method will be invoked on an invocation handler
     * when a method is invoked on a proxy instance that it is
     * associated with.
     *
     * @param   proxy the proxy instance that the method was invoked on
     *
     * @param   method the {@code Method} instance corresponding to
     * the interface method invoked on the proxy instance.  The declaring
     * class of the {@code Method} object will be the interface that
     * the method was declared in, which may be a superinterface of the
     * proxy interface that the proxy class inherits the method through.
     *
     * @param   args an array of objects containing the values of the
     * arguments passed in the method invocation on the proxy instance,
     * or {@code null} if interface method takes no arguments.
     * Arguments of primitive types are wrapped in instances of the
     * appropriate primitive wrapper class, such as
     * {@code java.lang.Integer} or {@code java.lang.Boolean}.
     */
    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;

Parameters to describe :

proxy: The proxied class .

method: Method of the class being proxied when called Method object .

args: Parameters of the method of the class being proxied when calling .

3、 experimental data

3.1、Subject Interface

public interface Subject {
 
    String doSomething();
}

3.2、Subject Implementation class of interface RealSubject

public class RealSubject implements Subject {
 
    @Override
    public String doSomething() {
        System.out.println(" I'm real Object");
        return " I am a RealSubject";
    }

}

3.3、InvocationHandler Implementation class of ,Cache Call processor

 
package com.ceam.designer.proxy.jdk;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
public class Cache implements InvocationHandler {
 
    /**
     *  The real class encapsulated here can generally be :Object type 、 Interface type 、Class type 
     */
//    private Object object;
//
//    Cache(Object object) {
//        this.object = object;
//    }
 
    private Subject object;
 
    /**
     *  Initialize fields ,method.invoke(object, args) This field will be used in 
     * 
     * @param object  Real object 
     */
    Cache(Subject object) {
        this.object = object;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----Before handler----");
 
        //  Call the method of the real object , Return value result
        Object result = method.invoke(object, args);
        System.out.println((String)result);
 
        System.out.println("----After handler----");
 
        //  Return return value 
        return result;
    }
 
}

3.4、 Test class

package com.ceam.designer.proxy.jdk;
 
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
 
public class JDKProxyTest {
 
    public static void main(String[] args) {
        //  Declare a parent class to create a child class 
        Subject subject = new RealSubject();
        //  Encapsulate real classes 
        InvocationHandler cache = new Cache(subject);
        //  Generate proxy instance , Associated call handler 
        /**
         *  About the first and second parameters of the input parameter , It's usually : The first is the class loader for the interface , The second is new Class[]{ Interface Class}
         */
        Subject proxy = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
                new Class[]{Subject.class}, cache);
        String result = proxy.doSomething();
        System.out.println(" Return results :" + result);
 
        System.out.println("***********************************");
 
        Subject proxy2 = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
                subject.getClass().getInterfaces(), cache);
        proxy2.doSomething();
    }
 
}

3.5、 Console print results :

4、 increase InvocationHandler An implementation class SyCache

package com.ceam.designer.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

public class SyCache implements InvocationHandler {

    /**
     *  The real class encapsulated here can generally be :Object type 、 Interface type 、Class type 
     */
//    private Object object;
//
//    Cache(Object object) {
//        this.object = object;
//    }

    private Subject object;

    /**
     *  Initialize fields ,method.invoke(object, args) This field will be used in 
     *
     * @param object  Real object 
     */
    SyCache(Subject object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("----SyCache Before handler----");

        //  Call the method of the real object , Return value result
        Object result = method.invoke(object, args);
        System.out.println((String)result);

        System.out.println("----SyCache After handler----");

        //  Return return value 
        return result;
    }

}

5、 Modify and supplement JDKProxyTest

package com.ceam.designer.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class JDKProxyTest {

    public static void main(String[] args) {
        //  Declare a parent class to create a child class 
        Subject subject = new RealSubject();
        //  Encapsulate real classes 
        InvocationHandler cache = new Cache(subject);
        //  Generate proxy instance , Associated call handler 
        /**
         *  About the first and second parameters of the input parameter , It's usually : The first is the class loader for the interface , The second is new Class[]{ Interface Class}
         */
        Subject proxy = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
                new Class[]{Subject.class}, cache);
        String result = proxy.doSomething();
        System.out.println(" Return results :" + result);

        System.out.println("***********************************");

        Subject proxy2 = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
                subject.getClass().getInterfaces(), cache);


        //  Encapsulate real classes 
        InvocationHandler syCache = new SyCache(subject);
        proxy2 = (Subject)Proxy.newProxyInstance(Subject.class.getClassLoader(),
                subject.getClass().getInterfaces(), syCache);
        proxy2.doSomething();
    }

}

Print the results :

6、 summary

  No matter from idea The code in , Or the printed results can be seen : Use JDK A dynamic proxy , You can't make a few InvocationHandler The implementation classes of the interface are freely composed , Only one of them can be used to provide services for proxy classes .

3、 ... and 、 Decoration mode

1、 What problems can decoration pattern solve

    In practical production , New demands are always emerging . When there is a new need , It is necessary to add new functions to some components to meet these requirements . We can directly modify the existing component code and add new functions , This will obviously destroy the existing components stability , After modification , The entire assembly needs to be retested , Can be used online . This is a clear violation of “ to open up - closed ” principle .

    Decoration mode Can help us solve the above problems , Decoration mode can dynamically add functions to objects , It is based on combination Functional . In actual development , In the industry, it is recommended to use combination to expand the functions of the system , Less inheritance . Please remember one sentence : Combination over inheritance .

2、 From class diagram to decoration pattern

                                                                  chart 2-1 

Component( Components ): The component interface defines the behavior of all component implementation classes and all decorators .

CorrectComponent( Specific component implementation class ): The specific component implementation class implements Component( Components ) Interface .

Decorator( Decorator ): Parent of all decorators , It is an implementation of Component Abstract class of interface , And encapsulated a Component object , That is, the object to be decorated . And the object to be decorated as long as Component The type is enough , This realizes the combination and reuse of decorators . But it doesn't have to happen , Some designs can also omit it , And directly use the specific decorator , We have to be flexible .

CorrectDecorator( Specific ornaments ): Concrete decorator implementation classes , It will add some functions to the decorator , That is, the newly added requirement function is implemented in this implementation class . Of course, there can be more than one decorator , And they are all independent of each other .

The following class diagrams are some of my own research and design class diagrams , The main part is the above class diagram structure

                                                                chart 2-2

DecoratorWrapper From the picture 2-2 We can see that , It is responsible for creating decorators , See the following for the specific code 2.6.

2.1、Component Component interface

package com.ceam.designer.decorator.two;

/**
 * Component.java
 * <p>
 * Copyright 
 * All Rights Reserved.
 * Project: test-center
 * Description:
 *
 * @author : Administrator
 * History:
 * 2021-09-04 created by Administrator
 */
public interface Component {

    void doSomething();
}

2.2、CorrectComponent Specific component implementation class

package com.ceam.designer.decorator.two;

/**
 * CorrectComponent.java
 * <p>
 * Copyright 
 * All Rights Reserved.
 * Project: test-center
 * Description:
 *
 * @author : Administrator
 * History:
 * 2021-09-04 created by Administrator
 */
public class CorrectComponent implements Component {

    @Override
    public void doSomething() {
        System.out.println(" I am a specific component ");
    }
}

2.3、CorrectDecorator Specific decorators 1

package com.ceam.designer.decorator.two;

/**
 * CorrectDecorator.java
 * <p>
 * Copyright 
 * All Rights Reserved.
 * Project: test-center
 * Description:
 *
 * @author : Administrator
 * History:
 * 2021-09-04 created by Administrator
 */
public class CorrectDecorator implements Component {

    private final Component component;

    CorrectDecorator(Component component) {
        this.component = component;
    }

    @Override
    public void doSomething() {
        component.doSomething();
        this.enchange();
    }

    private void enchange() {
        System.out.println(" The rear enhancement ");
    }


}

2.4、CorrectDecorator2 Specific decorators 2

package com.ceam.designer.decorator.two;

/**
 * CorrectDecorator2.java
 * <p>
 * Copyright 
 * All Rights Reserved.
 * Project: test-center
 * Description:
 *
 * @author : Administrator
 * History:
 * 2021-09-04 created by Administrator
 */
public class CorrectDecorator2 implements Component {

    private final Component component;

    CorrectDecorator2(Component component) {
        this.component = component;
    }

    @Override
    public void doSomething() {
        component.doSomething();
        this.enchange();
    }

    private void enchange() {
        System.out.println(" The rear enhancement 2");
    }
}

2.5、Condition Auxiliary condition class

package com.ceam.designer.decorator.two;

/**
 * Condition.java
 * <p>
 * Copyright 
 * All Rights Reserved.
 * Project: test-center
 * Description:
 *
 * @author : Administrator
 * History:
 * 2021-09-04 created by Administrator
 */
public class Condition {

    public static Boolean d1;
    public static Boolean d2;

    public Condition d1(boolean d1) {
        this.d1 = d1;
        return this;
    }

    public Condition d2(boolean d2) {
        this.d2 = d2;
        return this;
    }
}

2.6、DecoratorWrapper Decorator packaging class

package com.ceam.designer.decorator.two;

/**
 * DecoratorWrapper.java
 * <p>
 * Copyright 
 * All Rights Reserved.
 * Project: test-center
 * Description:
 *
 * @author : Administrator
 * History:
 * 2021-09-04 created by Administrator
 */
public class DecoratorWrapper implements Component{

    private static Condition condition;
    public static Boolean d1;
    public static Boolean d2;

    DecoratorWrapper() {
    }

    DecoratorWrapper(Condition condition) {
        this.condition = condition;
    }

    @Override
    public void doSomething() {
        this.en();
    }

    private void en() {
        Component component = new CorrectComponent();
        if (Condition.d1) {
            component = new CorrectDecorator(component);
        }
        if (Condition.d2) {
            component = new CorrectDecorator2(component);
        }
        component.doSomething();
    }

    public DecoratorWrapper d1(boolean d1) {
        this.d1 = d1;
        return this;
    }

    public DecoratorWrapper d2(boolean d2) {
        this.d2 = d2;
        return this;
    }
}

2.7、 Test class

package com.ceam.designer.decorator.two;

/**
 * Test.java
 * <p>
 * Copyright 
 * All Rights Reserved.
 * Project: test-center
 * Description:
 *
 * @author : Administrator
 * History:
 * 2021-09-04 created by Administrator
 */
public class Test {

    public static void main(String[] args) {
//        Component component = new CorrectComponent();
//        component = new CorrectDecorator(component);
//        component = new CorrectDecorator2(component);
//        component.doSomething();
        Component component1 = new DecoratorWrapper(new Condition()
                .d1(false)
                .d2(false));
        component1.doSomething();

        System.out.println("2----------------------------------------");
        Component component2 = new DecoratorWrapper(new Condition()
                .d1(true)
                .d2(false));
        component2.doSomething();

        System.out.println("3----------------------------------------");
        Component component3 = new DecoratorWrapper(new Condition()
                .d1(true)
                .d2(true));
        component3.doSomething();

        System.out.println("4----------------------------------------");
        Component component4 = new DecoratorWrapper().d1(true).d2(true);
        component4.doSomething();
    }
}


2.8、 test result  

2.9、 summary

It can be seen from the experimental results that : Decorative patterns can be dynamically combined , Add functions to the decorated objects .

Four 、 What's the difference between dynamic proxy and decoration mode

What's the difference between dynamic proxy and decoration mode , I will not say more , Everything is in the experimental data , Please study carefully . After all, the author has made a lot of efforts , From the source code knowledge , After the experiment, the conclusion is , It has been summarized to the readers . If you have any questions, please leave a message , I try my best to answer .

原网站

版权声明
本文为[Cappuccino Haichen]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/173/202206220636473521.html