设计模式-代理模式之动态代理

基于子类的动态代理

通过一张图直观的看出:

所谓的代理模式,其实就是代理真实对象,达到增强真是对象的目的。
例如:上图中我在西安,要向联想北京总公司(真实对象)买电脑,西安有一个北京联想公司的代理商,显然跑去北京买太不划算了,所以可以直接向代理商买,代理商从中赚差价。总公司和代理商直接存在着一些关联,例如代理商需要从总公司进货,代理商的价格不能太高等…

  1. 静态代理:有一个类文件描述代理模式
  2. 动态代理:在内存中形成代理类
    1. 特点:字节码随用随创建,随用随加载
    2. 作用:不修改源码的基础上,对方法进行增强

动态代理示例:

  1. 联想总公司
	public interface SaleComputer {
	
	    public String sale(double money);
	
	    public void show();
	}
  1. 西安联想代理商
public class Lenvov implements SaleComputer {
	
	    public String sale(double money) {
	        System.out.println("花了"+money+"钱买电脑");
	        return "联想电脑...";
	    }
	
	
	    public void show() {
	        System.out.println("展示电脑...");
	    }
	}
  1. 方法执行
public class ProxyTest {
    public static void main(String[] args) {
        //1.创建真实对象
        final Lenvov lenvov = new Lenvov();

        //动态增强lenvov对象:
        /**
         * 参数:
         *  1.代理对象类加载器:lenvov.getClass().getClassLoader()
         * 用于加载代理对象字节码文件,和被代理对象使用相同的类加载器
         *  2.接口数组:保证了真实对象和代理对象实现相同的接口:lenvov.getClass().getInterfaces()
         *  3.
         *
         * 可以强制转为SaleComputer是因为:代理对象和正式对象实现了相同的接口
         */
        SaleComputer proxy_sc = (SaleComputer) Proxy.newProxyInstance(lenvov.getClass().getClassLoader(),
                lenvov.getClass().getInterfaces(),
                new InvocationHandler() {
            /**
             * 代理逻辑编写的方法:每一次代理对象调用方法,都会执行这个函数
             * @param proxy: 代理对象=proxy_sc
             * @param method :代理对象调用的方***被封装成Method对象
             * @param args :代理对象调用的方法实际传递的参数
             * @return :代理对象调用方法时的返回值
             * @throws Throwable
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("invoke...被执行了");
                if (method.getName().equals("sale")){
                    System.out.println("代理商专车接送过来买电脑...");
                    //1.增强参数
                    double money = (Double)args[0];
                    money *=0.85;
                    //2.增强方法执行的方法体
                    String invoke = method.invoke(lenvov, money);  //返回电脑
                    System.out.println("代理商专车接送回去...");
                    //3.增强返回值
                    return invoke+"鼠标垫";	//返回代理对执行的结果
                }else {
                    Object invoke = method.invoke(lenvov, args);
                    return null;
                }
            }
        });

        //3.调用方法
        String sale = proxy_sc.sale(7000);
        System.out.println(sale);
        //proxy_sc.show();
    }
}


内部逻辑就是用户给出7000块去买代理商电脑,代理商对收到的7000元进行85折,自己回收15%,85%付给了联想公司,所以这边输出:花了5950买电脑是其实是代理商向联系公司买电脑花的钱,而不是用户向联想公司花的钱,被赚差价了。
invoke函数返回值是代理对象的执行结果。

不基于子类的动态代理

  1. 被代理类
public class Lenvov {

    public String sale(double money) {
        System.out.println("花了"+money+"钱买电脑");
        return "联想电脑...";
    }


    public void show() {
        System.out.println("展示电脑...");
    }
}
  1. 测试方法:
/**
 * 不基于子类的动态代理
 *
 */
public class ProxyTest {
    public static void main(String[] args) {
        //1.创建真实对象
        final Lenvov lenvov = new Lenvov();

        //动态增强lenvov对象:

        Lenvov proxy_lenvov = (Lenvov)Enhancer.create(lenvov.getClass(),
                new MethodInterceptor() {
            /**
             * 执行被代理对象的任何方法都会经过该方法
             * 可以强制转为SaleComputer是因为:代理对象和正式对象实现了相同的接口
             * @param proxy :代理对象
             * @param method:代理对象执行的方***被封装成Method方法
             * @param args :代理对象调用的方法实际传递的参数
             * @param methodProxy:当前执行对象的代理方法
             * @return :代理对象调用方法时的返回值
             * @throws Throwable
             */
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("invoke...被执行了");
                if (method.getName().equals("sale")){
                    System.out.println("代理商专车接送过来买电脑...");
                    //1.增强参数
                    double money = (Double)args[0];
                    money *=0.85;
                    //2.增强方法执行的方法体
                    Object invoke = method.invoke(lenvov, money);  //返回电脑
                    System.out.println("代理商专车接送回去...");
                    //3.增强返回值
                    return invoke+"鼠标垫";	//返回代理对执行的结果
                }else {
                    Object invoke = method.invoke(lenvov, args);
                    return null;
                }
            }
        });
        String sale = proxy_lenvov.sale(10000);
        System.out.println(sale);
    }
}