zoukankan      html  css  js  c++  java
  • Java代理模式(静态代理&动态代理)

    一、概述

      定义:为其他对象提供一种代理,以控制这个对象的访问。

      代理模式的种类:静态代理和动态代理

    二、静态代理

      ps:我们创建一个Book用于基础操作,再创建一个JavaBook用来代理Book类的功能。

      1.Book.java

    package com.yw.reflectjavalib.proxy.staticproxy;
    
    /**
     * 定义一个book实体
     * create by yangwei
     * on 2020-02-16 17:48
     */
    public class Book {
        public void doWork() {
            System.out.println("读书");
        }
    }
    

      2.JavaBook.java

    package com.yw.reflectjavalib.proxy.staticproxy;
    
    /**
     * java实体
     * create by yangwei
     * on 2020-02-16 17:49
     */
    public class JavaBook {
        private Book book;
    
        public JavaBook(Book book) {
            this.book = book;
        }
    
        public void doWork() {
            System.out.println("Java");
            book.doWork();
        }
    }
    

      3.main方法测试

    package com.yw.reflectjavalib.proxy.staticproxy;
    
    /**
     * 静态代理测试
     * create by yangwei
     * on 2020-02-16 17:47
     */
    public class StaticProxyDemo {
        public static void main(String[] args) {
            Book book = new Book();
            //这里由于Javabook中有Book类的引用,所以JavaBook除了可以做自己的事情外,可以顺便把Book的工作给做了。
            //也就是JavaBook代理了Book了的所有功能。这就是静态代理,非常的简单。
            //通常这种模式也可以延伸成为装饰模式,即JavaBook把Book类给装饰的更强大了。
            JavaBook javaBook = new JavaBook(book);
            javaBook.doWork();
        }
    }
    

      

    三、动态代理

      在上面的例子中我们虽然使用JavaBook代理了Book类,但是仔细一想这样做是有问题的。例如:每一个类都需要有一个对应的Proxy类,随着类增多则代理类也会增加很多。下面介绍一种只需要一个代理类就能搞定的方法——动态代理。

       在java.lang.reflect包中有一个Proxy类。Proxy类的Proxy.newProxyInstance(ClassLoader,Class[] interfaces,InvocationHandler)方法可以将目标对象进行注入,并实现对目标对象的修改。

      参数介绍:

      1.ClassLoader classLoader 目标对象的classloader

      2.Class<?>[] interfaces 目标对象实现的接口类型

      3.InvocationHandler handler 一个实现了InvocationHandler的对象,通过构造方法把目标对象注入,并在这个自定义类中做一些自定义的操作。

    下面通过一个简单的例子玩一下动态代理,加深对动态代理的理解。ps:输出水果的颜色。

      1.IFruits.java

      

    package com.yw.reflectjavalib.proxy.staticproxy.dnyproxy;
    
    /**
     * 定义一个水果的接口
     * create by yangwei
     * on 2020-02-16 18:10
     */
    public interface IFruits {
        /**
         * 水果的颜色
         */
        String getColor();
    }
    

      

      2.Apple.java

    package com.yw.reflectjavalib.proxy.staticproxy.dnyproxy;
    
    /**
     * create by yangwei
     * on 2020-02-16 18:12
     */
    public class Apple implements IFruits {
        @Override
        public String getColor() {
            return "红色";
        }
    }
    

      

      3.MyInvocationHandler.java

    package com.yw.reflectjavalib.proxy.staticproxy.dnyproxy;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
     * create by yangwei
     * on 2020-02-16 18:13
     */
    public class MyInvocationHandler implements InvocationHandler {
        private Object target;
    
        public MyInvocationHandler(Object obj) {
            this.target = obj;
        }
    
        @Override
        public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
            System.out.print("水果的颜色:");
            return method.invoke(target, objects);
        }
    }
    

      

      4.DnyProxyDemo.java

    package com.yw.reflectjavalib.proxy.staticproxy.dnyproxy;
    
    import java.lang.reflect.Proxy;
    
    /**
     * 动态代理测试
     * create by yangwei
     * on 2020-02-16 18:01
     */
    public class DnyProxyDemo {
        /**
         * 动态代理
         *
         * @param args
         */
        public static void main(String[] args) {
            //创建一个Apple实例
            IFruits iFruits = new Apple();
            //动态代理Apple,代理后把代理对象返回,由于是面向接口编程,所以可以直接把返回结果转换为接口类型。
            //而MyInvocationHandler中已经对代理对象apple做了相关的操作。例如:加上了"水果的颜色"
            //所以打印出来的值为:水果的颜色为:红色
            //如果去掉代理类,那打印结果只能是:红色。
            //这就是动态带来的神奇之处,只要把目标代理对象传进去,就可以对目标代理对象做一些个性化的包装
            //动态代理相较于静态代理的优势是,我们不必为每一个对象都创建一个代理对象了。直接使用Proxy.newProxyInstance弄出来一个就OK了。
            IFruits object = (IFruits) Proxy.newProxyInstance(iFruits.getClass().getClassLoader(), iFruits.getClass().getInterfaces(), new MyInvocationHandler(iFruits));
            System.out.println(object.getColor());
        }
    }
    

      以上就是动态代理的完整例子,在以上例子中,如果我们不使用动态代理,直接处处apple的颜色,只能得到“红色”。使用动态代理后会在水果颜色前面加上描述:“水果的颜色为:红色”,大家可以运行下试试,感受下。

  • 相关阅读:
    47数据结构与算法分析之---查找的基本概念
    46数据结构与算法分析之---排序方法比较
    45数据结构与算法分析之---基数排序
    44数据结构与算法分析之---归并排序
    43数据结构与算法分析之---选择排序
    42数据结构与算法分析之---交换排序
    41数据结构与算法分析之---插入排序
    54数据结构与算法分析之---哈希查找
    40数据结构与算法分析之---排序的基本概念
    37数据结构与算法分析之---关键路径
  • 原文地址:https://www.cnblogs.com/tony-yang-flutter/p/12317983.html
Copyright © 2011-2022 走看看