JavaEE学习日志(七十九): 装饰者设计模式,动态代理

JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)

动态代理

装饰者设计模式

装饰者设计模式(静态代理)和动态代理的目的:增强原有对象的功能(连接池方法close)

设计模式基于面向对象思想
装饰思想在IO中大量应用,所有的缓冲流、打印流都叫装饰流
Reader(原始流) BufferedReader(装饰流)
如:地暖,就是地面的装饰者,保留地面原有的承重功能,添加了取暖效果
使用IO流时,new BufferedReader(原始流)

实现装饰者模式的步骤

  1. 被装饰者和装饰者必须拥有相同的父类,或者实现相同的接口
  2. 使用装饰者的同时,必须提供被装饰者,new 装饰者(被装饰者)
  3. 方法如果不需要增强,直接使用。需要增强,定义或重写

自定义装饰流MyBufferedReader

自定义一个装饰类
模拟方法readLine()

package com.itheima.decoration;

import java.io.IOException;
import java.io.Reader;

/*
    自定义一个装饰类
    模拟方法readLine()
 */
public class MyBufferedReader extends Reader {
    private Reader r;
    //new MyBufferedReader(FileReader())
    public MyBufferedReader(Reader r){
        this.r = r;
    }
    /*
        实现读取文本一行的功能
        原有的功能不能破坏,read()可以读取一个字符
        利用原有功能read(),实现读取一行
     */
    public String readLine() throws IOException{
        int len = 0;
        StringBuilder sb = new StringBuilder();
        //read()返回-1,文件结束
        while ((len = r.read())!= -1){
            //判断读取到的字符是不是\r, int和char做运算,char自动变成int
            if(len == '\r'){
                continue;
            }
            //判断读取到的字符是不是\n
            if(len == '\n'){
                //这一行读取结束
                //从容器中,取出字符串返回
                return sb.toString();
            }
            //有效的字符,追加缓冲区
            sb.append((char)len);
        }
        //文件读取结束,判断缓冲区中是否还有内容
        if(sb.length()>0){
            return sb.toString();
        }
        return null;
    }

    @Override
    public int read(char[] chars, int i, int i1) throws IOException {
        return 0;
    }

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

测试类

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

在这里插入图片描述

类加载器

类加载器(ClassLoader)
作用:加载运行的class文件进入内存,并创建class对象。
在这里插入图片描述

动态代理原理

在这里插入图片描述

Proxy工具类

实现动态代理

  • 被代理对象 :ArrayList (方法:add,size,get,remove)
  • 代理对象,只要使用被代理对象的方法,通过代理对象
    如:代理对象让别人只能用ArrayList的size方法

Proxy类的方法

  • static Object newProxyInstance​(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h) 返回指定接口的代理实例,该接口将方法调用分派给指定的调用处理程序。

方法参数:

  1. 传递被代理对象的加载器ArrayList.class.getClassLoader
  2. 被代理对象实现的所有接口ArrayList.class.getInterfaces
  3. InvocationHandler接口实现类,代理对象执行的方法

返回值Object:被代理后的对象

InvocationHandler接口方法

  • Object invoke​(Object proxy, 方法 method, Object[] args) 处理代理实例上的方法调用并返回结果。

方法参数:

  1. proxy: 被代理的对象ArrayList
  2. method:被代理对象的方法,如:add,size,get,remove
  3. args:被代理对象的方法的实际参数

返回值Object:执行被代理对象的方法的返回值。如:被代理对象的size() 返回长度

实现动态代理:让被代理对象ArrayList只能调用size()方法

public class Demo {
    public static void main(String[] args) {
        ArrayList<String> list = new ArrayList<>();
        list.add("1");
        list.add("2");
        list.add("3");
        //方法getProxy,返回被代理后的对象
        List<String> proxyList = getProxy(list);
        System.out.println(proxyList.size());//3
        System.out.println(proxyList.get(0));//java.lang.RuntimeException: 禁止调用该方法
    }
    /*
        定义方法,实现ArrayList对象的动态代理
        生成被代理的对象,执行集合的方法size被允许
        传递被代理的对象,返回代理后的对象
     */
    public static List<String> getProxy(ArrayList<String> list){
        //传递被代理对象的加载器
        //传递被代理对象实现的接口
        //传递InvocationHandler接口的实现类
        //返回值:被代理后的对象
        return (List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
            /*
                被代理对象执行的方法
                调用集合的任意方法,都会执行invoke
                proxy:被代理的对象
                method:被代理对象调用的方法
                objects:调用方法传递的实际参数
                返回值:被调用方法的返回值

                Method类方法:getName()获取执行的方法名
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                //不是size方法,就不让调用
                String name = method.getName();
                if("size".equals(name)){
                    //是size,允许调用方法,size()返回长度
                    return method.invoke(list,args);
                }else {
                    throw new RuntimeException("禁止调用该方法");
                }
            }
        });
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值