代理模式补充上期

一、代理模式

定义

为其他对象提供一种 代理 以控制对这个对象的访问。. 在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。. 著名的代理模式例子为 引用计数 (英语:reference counting)指针对象。. 当一个复杂对象的多份副本须存在时,代理模式可以结合 享元模式 以减少存储器用量。. 典型作法是创建一个复杂对象及多个代理者,每个代理者会引用到原本的复杂对象。. 而作用在代理者的运算会转送到原本对象。. 一旦所有的代理者都不存在时,复杂对象会被移除。

二、静态代理

(一)静态代理

在学习代理模式时,我使用一个瓜甜不甜案例;

1.接口:Transportation(交通工具) 自定义接口,定义run()方法。
2.被代理类:Car类实现Transportation接口。
3.代理类:CarHanlderWork(事务代理类)CarHanlderTime(时间代理类)。
4.测试类:Client

(二)静态代理简单实现
继承实现静态代理:
public interface Tranfertaction {
    void run();
}
/**
 * 需求,需要给实现了Transportation接口的子类里重写的run方法加上前后日志记录
 * 可以通过继承的方式给Car创建一个代理对象。并重写Car的方法,在重写的方法中调用父类的逻辑。并在调用前后加上日志记录
 */
public class Car implements Tranfertaction{
    @Override
    public void run() {
        System.out.println("开车创死你");
    }
}
//测试类main方法测试
public class Client {
    public static void main(String[] args) {
        CarHanlderWork carHanlderWork = new CarHanlderWork();
        carHanlderWork.run();
    }
}
组合或聚合实现静态代理:
/**
 * 通过聚合或组合实现代理,该种代理称为静态代理:
 *  定义一个类,内部持有被代理对象的一个引用,此处的引用最好使用被代理对象的父类
 *  实现一个方法,在方法内部调用被代理对象的方法。并在调用前后加日志记录
 */
 public class CarHanlerTime {
    Transportation  target;
    public CarHanlerTime(Transportation  target) {
        this.target = target;
    }
    public void invoke() {
        System.out.println("开车时间:" + System.currentTimeMillis());
        target.run();
        System.out.println("创死时间:" + System.currentTimeMillis());
    }
}
//测试
public class Client {
    public static void main(String[] args) {
        Car car = new Car();
        CarHanlerTime carHanlerTime = new CarHanlerTime(car);
        carHanlerTime.invoke();
    }
}

多个日志叠加,创建两个日志代理类,实现和Car一样的父类接口。

public class CarHanlerTime implements Transportation{
    Transportation  target;
    public CarHanlerTime(Transportation  target) {
        this.target = target;
    }
    public void run() {
        System.out.println("开车时间:" + System.currentTimeMillis());
        target.run();
        System.out.println("创死时间:" + System.currentTimeMillis());
    }
}
public class CarHanlerWork2 implements Transportation {
    Transportation  target;
    public CarHanlerWork2(Transportation  target) {
        this.target = target;
    }
    public void run() {
        System.out.println("开车:" );
        target.run();
        System.out.println("熄火:" );
    }
}
public class Client {
    public static void main(String[] args) {
        Car car = new Car();
        CarHanlerTime carHanlerTime = new CarHanlerTime(car);
        CarHanlerWork2 carHanlerWork2 = new CarHanlerWork2( carHanlerTime);
        carHanlerTime.run();
    }
}

三、动态代理

(一)动态代理
是在内存中生成代理对象的一种技术
无需手写代理类,也不会存在代码编译的过程。运用在内存中生产代理类的技术在JVM的运行区造一个代理对象,只需对需要修改的部分进行编辑。
(二)动态代理JDK使用
实际上就是在内存中生产一个对象,该对象实现了指定的目标对象的所有接口,代理对象和目标对象是兄弟关系。
jdk自带动态代理技术,需要使用一个静态方法来创建代理对象,它需要目标对象必须实现接口,生产的代理对象和原对象都实现相同的接口。

public class CarHanlerTime implements InvocationHandler {
    Transportation  target;
    public CarHanlerTime(Transportation  target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("开车时间:" + System.currentTimeMillis());
        target.run();
        System.out.println("创死时间:" + System.currentTimeMillis());
        return null;
    }
}
//
public class Client {
    public static void main(String[] args) {
        Car car = new Car();
        CarHanlerTime carHanlerTime = new CarHanlerTime(car);
        Transportation instance = (Transportation) Proxy.newProxyInstance(Transportation.class.getClassLoader(),
                new Class[]{Transportation.class},  carHanlerTime);
        instance.run();
    }
}

(三)动态代理简单实现,自己通过反射手写,并试图理解。

/**
 * 使用动态代理实现日志记录
 * 定义一个日志记录的代理类,并实现InvocationHandler接口,重写内部的invoke方法。加上要代理的逻辑
 * 在该代理类中需要持有一个成员变量,该变量可以代表java中的任意对象.
 */
public class LogHandler implements InvocationHandler {
    private Object target;

    /**
     * 该构造方法的作用:
     *      用于接收被代理的对象。
     * @param target
     */
    public LogHandler(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("启动");
        //调用被代理对象target的指定方法method,该方法由生成的代理对象中的方法传入。
        method.invoke(target);
        System.out.println("熄火");
        return null;
    }
}
public class Client {
    public static void main(String[] args) throws Exception {
        Man man = new Man();
        LogHandler handler = new LogHandler(man);
        Person person = (Person) Proxy.newProxyInstance(Person.class, handler);
        person.eat();
        person.sleep();
    }
}
public class Proxy {
    public static Object newProxyInstance(Class infc, InvocationHandler handler) throws Exception {
        String methodStr = "";
        Method[] methods = infc.getMethods();
        for (Method method : methods) {
            methodStr += "    public void " + method.getName() + "(){\n" +
                    "        try{\n" +
                    //获取被代理对象要被执行的方法
                    "           Method md = " + infc.getName() + ".class.getMethod(\"" + method.getName() + "\");\n" +
                    "           h.invoke(this, md);\n" +
                    "        }catch(Exception e) {}\n" +
                    "    }\n";
        }
        String src =
                "import com.proxy.Person;\n" +
                "import com.proxy.InvocationHandler;\n" +
                "import java.lang.reflect.Method;\n" +
                "public class Proxy1 implements " +  infc.getName() + "{\n" +
                "    private InvocationHandler h;\n" +
                "    public Proxy1(InvocationHandler h) {\n" +
                "        this.h = h;\n" +
                "    }\n" +
                methodStr +
                "}";
        //此处文件需要写到某个盘下,不建议写道项目路径,因为不能及时生成文件,要等到程序跑完才能生成文件
        //这样会导致反射去加载类时找不到生成的文件
        String fileName = "D:/qf/src/Proxy1.java";//System.getProperty("user.dir")+"/Proxy1.java";
        File f = new File(fileName);
        FileWriter fw = new FileWriter(f);
        fw.write(src);
        fw.flush();
        fw.close();
        //javac TimeHandler01.java
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        StandardJavaFileManager fileManager = compiler.getStandardFileManager(null, null, null);
        Iterable iterable = fileManager.getJavaFileObjects(fileName);
        JavaCompiler.CompilationTask task = compiler.getTask(null, fileManager, null, null, null, iterable);
        task.call();
        fileManager.close();

        URL[] urls = new URL[]{new URL( "file:/D:/qf/src/")};
        URLClassLoader classLoader = new URLClassLoader(urls);
        Class clazz = classLoader.loadClass("Proxy1");
        Constructor<?> constructor = clazz.getDeclaredConstructor(InvocationHandler.class);
        Object obj = constructor.newInstance(handler);
        return obj;
    }
}

public interface InvocationHandler {
    void invoke(Object o, Method m) throws Exception;
}
public class LogHandler implements InvocationHandler {
    Object target;
    public LogHandler(Object target) {
        this.target = target;
    }
    @Override
    public void invoke(Object o, Method m) throws Exception {
        System.out.println("Log你好吗");
        m.invoke(target);
        System.out.println("Log哦哦哦哦哦");
    }
}

public interface Person {
    void eat();
    void sleep();
}

public class Man implements Person {
    @Override
    public void eat() {
        System.out.println("在吃饭-----");
    }

    @Override
    public void sleep() {
        System.out.println("在睡觉----");
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值