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());
            …
        }
}

 

posted @ 2019-12-04 20:09  魏小哥  阅读(980)  评论(0编辑  收藏  举报