Java中代理和裝飾者模式的區別


裝飾模式:以對客戶端透明的方式擴展對象的功能,是繼承關系的一個替代方案;

代理模式:給一個對象提供一個代理對象,並有代理對象來控制對原有對象的引用;


裝飾模式為所裝飾的對象增強功能;代理模式對代理的對象施加控制,並不提供對象本身的增強功能

簡而言之,裝飾者是指的是自身,對功能的增強,而另一種是調用接口,實現對代理對象的控制

 

在Spring AOP中,主要使用了兩種代理方式:jdkProxy、cjlibProxy

cjlibProxy:

package com.cjlib;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author weining
 * @date 2019/10/31 8:45
 */
public class CglibProxyExample implements MethodInterceptor {

    public Object getProxy(Class cls) {
        //CGLIB enhancer 增強類對象
        Enhancer enhancer = new Enhancer();

        //設置增強類型
        enhancer.setSuperclass(cls);

        //定義邏輯對象,要求實現當前對象實現MethodInterceptor方法
        enhancer.setCallback(this);

        //返回代理對象
        return enhancer.create();
    }

    /**
     * 代理邏輯方法
     *
     * @param o           代理對象
     * @param method      方法
     * @param objects     方法參數
     * @param methodProxy 方法代理
     * @return 代理邏輯返回
     * @throws Throwable
     */
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("調用真是對象之前");
        Object invokeSuper = methodProxy.invokeSuper(o, objects);
        System.out.println("調用真是對象之后");

        return invokeSuper;
    }
}

  測試方法:

package com.cjlib;

import com.jdk.HelloWorld;
import com.jdk.impl.HelloWorldImpl;

/**
 * @author weining
 * @date 2019/10/31 9:03
 */
public class testCGLIBProxy {
    public static void main(String[] args) {
        CglibProxyExample cglibProxyExample = new CglibProxyExample();
        HelloWorld helloWorld = (HelloWorldImpl) cglibProxyExample.getProxy(HelloWorldImpl.class);
        helloWorld.sayHello();
    }
}

  

 

jdkProxy:

package com.jdk;

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

/**
 * @author weining
 * @date 2019/10/31 8:29
 * 在jdk動態代理時 必須要實現InvocationHandler接口
 * 自動生成接口中的invoke方法
 */
public class JdkProxyExample implements InvocationHandler {

    private Object target = null;

    public Object bind(Object target){
        this.target = target;
        /*
            三個屬性分別是:類加載器,把生成的動態代理對象掛在哪個接口之上,定義實現方法邏輯的代理類
         */
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    /**
     * invoke可以實現代理對象
     * @param proxy bind 返回的對象
     * @param method 當前調度的方法
     * @param args 調度方法的參數
     * @return 代理的結果返回
     * @throws Throwable
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("進入代理邏輯方法");
        System.out.println("在調用真實對象的服務");
        Object obj=method.invoke(target,args);
        System.out.println("在調用真實對象之后的服務");
        return obj;
    }
}

這時,創建一個HelloWorld接口:

package com.jdk;

/**
 * @author weining
 * @date 2019/10/31 8:27
 */
public interface HelloWorld {
    public void sayHello();
}

創建接口的實現類:

package com.jdk.impl;

import com.jdk.HelloWorld;

/**
 * @author weining
 * @date 2019/10/31 8:27
 */
public class HelloWorldImpl implements HelloWorld {
    public void sayHello() {
        System.out.println("Hello,World!");
    }
}

最后調用測試方法:

package com.jdk;

import com.jdk.impl.HelloWorldImpl;

/**
 * @author weining
 * @date 2019/10/31 8:40
 */
public class test {
    public static void main(String[] args) {
        JdkProxyExample jdkProxyExample = new JdkProxyExample();

        HelloWorld proxy = (HelloWorld) jdkProxyExample.bind(new HelloWorldImpl());
        proxy.sayHello();

    }
}

兩者的區別

1)JDK動態代理只能對實現了接口的類生成代理,而不能針對類。

2)CGLIB是針對類實現代理,主要是對指定的類生成一個子類,覆蓋其中的方法,

     並覆蓋其中方法實現增強,但是因為采用的是繼承,所以該類或方法最好不要聲明成final,

     對於final類或方法,是無法繼承的。

 

裝飾者模式:

//裝飾器模式
public class Decorator implements Component{
        private Component component;
        public Decorator(Component component){
            this.component = component
        }
       public void operation(){
            ….
            component.operation();
            ….
       }
}
//裝飾器的客戶
public class Client{
        public static void main(String[] args){
            //客戶指定了裝飾者需要裝飾的是哪一個類
            Component component = new Decorator(new ConcreteComponent());
            …
        }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM