装饰者模式&&动态代理

装饰者模式&&动态代理

今日任务:
1.学习动态代理技术 使用动态技术完成无侵入式的增强事务逻辑

/

装饰者模式

	装饰者设计模式 (静态代理)
	目的: 增强原有对象的功能
	应用点: IO流对象 (Writer Reader) 基础流
	BufferedXXX,打印流,装饰类
	
    装饰者设计模式 思想:
	增强原有对象功能
	Reader 原有功能,基础流
	BufferedReader 装饰流
比喻:
	 地暖,取暖
	 地面,铺上一层地暖
     地面(承重)
	
	 使用装饰对象,必须先存在被装饰对象
	
	 new BufferedReader(Reader r)
	 不改变原有功能,在原有的功能上进行增强
	 
装饰者设计模式 || 静态代理:
	无侵入式编程:不破坏上层代码
	1.装饰者类跟原本实现类必须实现同一个接口(面向接口的特征 无侵入式编程)
	2.装饰者类对象必须持有原本对象的  我不是替代你的 是补充增强
	3.不需要增强的方法 调用原来对象
	4.需要增强的 我们自己补充逻辑

在这里插入图片描述
代码实现1:
CarTest

public class CarTest {
	public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
		Car car = new QQWrapper(new QQ());
		car.run();
	}
}

接口Car

public interface Car {
    void run();
    void stop();
    int oilTank();
    void driver(String driverName);
    Car didi();
}

实现类QQ

public class QQ implements Car {

	@Override

	public void run() {

		try {
			Thread.sleep(1000);
			System.out.println("qq完成百公里加速");
		} catch (Exception e) {
		}

    }
	后续方法..........
}

代理QQWrapper

public class QQWrapper implements Car {
	private Car qq;
	
	public QQWrapper(Car qq) {
		super();
		this.qq = qq;
	}

	@Override
	public void run() {
		long start = System.currentTimeMillis();
		qq.run();
		long end = System.currentTimeMillis();
		System.out.println("百公里加速用时"+(end-start));
	}

	后续方法.....
}

代码实现2:
在这里插入图片描述

Test.java

public class Test {
    public static void main(String[] args)throws IOException {
        //创建原始流对象
        FileReader fr = new FileReader("c:\\1.txt");
        //创建自己定义的装饰类,构造方法,传递原始流
        MyBufferedReader my = new MyBufferedReader(fr);
        String line = null;
        while ( (line = my.readLine())!=null){
            System.out.println(line);
        }
        my.close();
    }
}

MyBufferedReader.java

/**
 * 装饰设计思想,自定义装饰类
 * 模拟出 BufferedReader 的方法readLine()
 *
 * new MyBufferedReader(new FileReader(文件路径))
 * 传递来的流FileReader,本身具有读取功能  read(),读取一个字符
 * 利用原有的流方法read(),实现读取一行
 *
 * len=='\r'  int和char计算,char提示为int计算
 */
public class MyBufferedReader extends Reader {

    private Reader r ;//new FileReader(文件路径);
    //构造方法,装饰哪个流,传递过来
    public MyBufferedReader(Reader r){
        this.r = r;
    }
    //创建方法,实现读取文本一行
    public String readLine()throws IOException{
        int len = 0;
        //创建字符串缓冲区对象
        StringBuilder sb = new StringBuilder();
        //利用原始流 方法read()读取单个字符
        //判断是不是读取到了换行符
        while ( (len=r.read())!=-1 ){
             //判断是不是 \r
            if(len=='\r')
                continue;
            //判断是不是 \n
            if(len == '\n')
                //一行读取结束了,容器中的字符取出,返回
                //字符串缓冲区中的内容变成String对象返回
                return  sb.toString();
            //判断不是\r也不是\n 读取到是个有效字符
            //字符追加缓冲区
            sb.append((char)len);
        }
        //循环结束了,read()返回-1,文件读取完毕
        //判断缓冲区是不是有字符
        if(sb.length()>0)
            return sb.toString();

        return  null;
    }


    @Override
    public int read(char[] cbuf, int off, int len) throws IOException {
        return 0;
    }

    @Override
    public void close() throws IOException {
        r.close();
    }
}

动态代理

动态代理原理
在这里插入图片描述
Test

/**
 *   实现动态代理程序
 *   创建代理对象(经纪人)
 *   被代理对象(明星) ArrayList
 *
 *   我是调用者,调用目标对象的方法  ArrayList
 *   通过代理对象(经纪人)
 *   方法: add  remove  size(运行) get
 *
 *   Proxy.newInstance( 被代理对象的类加载器,被代理对象实现的接口, 代理对象执行代理方法的接口 ) 返回的是代理对象
 *   InvocationHandler 是代理对象实现代理功能接口
 *     方法  Object invoke(被代理对象,被代理对象的方法,被代理对象方法的实际参数)
 *        返回值,被代理对象执行方法后的结果
 *
 *
 * Object Proxy.newInstance( ArrayList.class.getClassLoader,
 *                    ArrayList.class.getInterfaces, 代理对象执行代理方法的接口 InvocationHandler ) 返回的是代理对象
 *
 *  class A implements InvocationHandler{
 *      public Object invoke(ArrayList,被代理对象方法 get, 被代理方法的实际参数 1){
 *
 *          返回的是 get()方法结果
 *      }
 *
 *  }
 */
public class Test {
    public static void main(String[] args) {
        List<String> arrayList = new ArrayList<String>();
        arrayList.add("1");
        arrayList.add("2");
       //调用方法,传递被代理对象,返回代理后的对象
       List<String> newList = (List<String>) getProxy(arrayList);
       System.out.println(newList.get(0));
    }

    /**
     * 定义方法,实现返回代理对象
     */
    public  static Object getProxy(List<String> list){
        //调用工具类方法
        // 代理对象类的加载器
        // 被代理对象实现的接口
        // InvocationHandler接口实现类
      return  Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            /**
             *  proxy被代理对象 list
             *  method 调用对象的方法
             *  args 方法参数
             *  返回: 执行方法后的结果
             */
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //Method对象,可以获取到被代理对象调用的方法名
                String methodName = method.getName();
                if("size".equals(methodName)){
                    //运行执行
                  return   method.invoke(proxy,args);
                }else{
                    //不是 指定方法,不能运行
                   throw new RuntimeException("不能使用该方法");
                   // return null;
                }
            }
        });
    }
}

类的加载器
在这里插入图片描述

/**
 *  获取一个类的加载器
 *  java.lang.ClassLoader 类的加载器
 *  类的加载器,是个对象, 都是ClassLoader对象
 *  任何一个类,静态属性class,获取该类的class文件对象
 *  通过class文件对象的方法 getClassLoader()获取他的加载器
 */
public class Test {
    public static void main(String[] args) {
        ClassLoader classLoader = Test.class.getClassLoader();
        System.out.println(classLoader);

        classLoader = String.class.getClassLoader();
        System.out.println(classLoader);

        classLoader =  DNSNameService.class.getClassLoader();
        System.out.println(classLoader);
    }
}
使用动态代理技术
	保留 无侵入增强的特色
	去除 写大量代码 写大量类

	jdk动态代理
		在java.lang.reflect 包 有一个类 Proxy 有一个方法 帮助实现
		static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) ;

		使用这个方法  可以直接帮你产出一个已经被增强过的对象
		三个参数:
			ClassLoader:类加载器 随便一个类加载器(给一个除去特殊 引导类加载,和扩展类加载 使用自己引入第三方自己的类 得到那个类加载器)
			interfaces:接口数组 传入原本对象实现所有接口数组 
			InvocationHandler:执行处理类对象(难点);

		实现它InvocationHandler接口
			Object invoke(Object proxy, Method method, Object[] args)  
			
			proxy:代表的是 即将返回的增强对象
			method:代表的是增强对象调用方法的时候的方法本身
			args:代表的是增强对象调用方法传入实参本身

Demo01.java

public class Demo01 {
    public static void main(String[] args) {
        //目的增强逻辑
        QQ qq=new QQ();

        //换动态代理 返回一个增强的对象
        Car zq = (Car) Proxy.newProxyInstance(
                Demo01.class.getClassLoader(),
                qq.getClass().getInterfaces(),
                new MyInvocationHandler(qq)
        );

        //zq.run();
        //zq.stop();
        //zq.driver("小明");
        //int i = zq.oilTank();
        //System.out.println(i);
        zq.didi().didi().didi();
    }

    private static class MyInvocationHandler implements InvocationHandler{
        private Car car;

        public MyInvocationHandler(Car car) {
            this.car = car;
        }

        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //System.out.println(proxy);


            //System.out.println(method.getName());
            if ("run".equals(method.getName())){
                long start = System.currentTimeMillis();
                //  平常调用方法 对象.方法
                //  方法.invoke(对象)

                method.invoke(car);


                long end = System.currentTimeMillis();
                System.out.println("百公里加速用时"+(end-start));

            }else if("driver".equals(method.getName())) {
                System.out.println(Arrays.toString(args));
                method.invoke(car,args[0]+"的媳妇儿");


            }else if("oilTank".equals(method.getName())) {

                Integer invoke = (Integer) method.invoke(car, args);
                return invoke+100;


            }else if("didi".equals(method.getName())) {
                System.out.print("增强对象在调用:");
                method.invoke(car);
                return proxy;


            }else {
                //调用原来的方法
                method.invoke(car);
            }



            return null;
        }
    }

}

invoke方法参数里输出proxy报错

在这里插入图片描述
解决方法
看源码:
在这里插入图片描述
直接输出proxy,调用toString方法,toString方法里是invoke,这样无限循环造成死递归,栈溢出,就会报错

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值