代理模式

代理模式

代理就是把事情交给别人做,虽然自己能做

常见的代理就是租房

​ 租客------------>租房

​ 中介------------>租房

​ 中介是专门租房的,对市场了解,我们可以把租房这件事交给中介去做,这样就可以减轻我们的负担

​ 交给专门做租房这一件事的人去做

(在很多方法执行前后都有相同或相似的操作时,我们就可以有一个代理类,让他去处理,这样就不用每个类当中一个一个的写方法了)

这就是单一职责原则(一个类或者方法只做一件事)

静态代理

租房

通过静态代理的方式实现 中介租房

​ 租客(Class Renter)

​ 中介(Class MiddleMan)

​ 租房(method rentHouse )

中介和租客在租房的时候需要遵守一种规范(租房的规范),那么租房这个行为就可以在一个接口(Interface Rent)中体现

接口不仅是对共性的抽取,同时也是一种规范,通过这种规范去约束实现类的行为

租房接口

public interface Rent {
    public abstract void rentHouse();
}

租客类

public class Renter implements Rent {
    @Override
    public void rentHouse() {
        System.out.println("租客租房");
    }
}

中介类

public class MiddleMan implements Rent{
    private Rent rent;
    public MiddleMan(Rent rent){
        this.rent = rent;
    }


    @Override
    public void rentHouse() {
        // 业务的拓展
        System.out.println("等待租客找中介租房");
        rent.rentHouse(); // 代理租客的行为
        System.out.println("中介帮租客选好房了");
    }
}

​ 中介租房是一个现实中的代理,但是似乎和我们现实中的有不同之处,当我们找中介租房的时候我们就完全不用管了,但是在上述的例子当中,实际上租客还是做了租房的这个行为。

​ 代码中的代理,比较容易理解的是 登录操作,当我们的账号异地登录的时候系统会通知你在什么时候、什么地点登录了,这是为了确保你的账号安全。

但在很久之前没有这个功能,如果你异地登录了也不会通知你,说明以前没有这个功能,现在 在 之前功能的基础之上添加了 记录登录时间、地点(日志)的功能。

根据设置模式中的“开闭原则”(对修改关闭,对拓展开放),我们就不能对之前的代码进行修改,我们就可以通过代理模式来解决。

登录

在登录操作中添加登录时间

对于登录操作的业务(业务一般都有一个接口,用于规范行为)

接口

public interface Login {
    public abstract void userLogin();
}

用户类(登录)

public class User implements Login{
    @Override
    public void userLogin() {
        System.out.println("用户登录了");
    }
}

代理类

public class LoginProxy implements Login {
    private Login login;

    public LoginProxy(Login login) {
        this.login = login;
    }

    @Override
    public void userLogin() {
        System.out.println("登录时间: " + getTime());

        login.userLogin();

        System.out.println("用户登录成功了");
    }
	/**
	 * 获取登录时间 
	 */
    private String getTime() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = sdf.format(date);
        return time;
    }
}

测试类

public class Test {
    public static void main(String[] args) {
        User user = new User();
        LoginProxy loginProxy = new LoginProxy(user);
        loginProxy.userLogin();
    }
}

动态代理

动态代理就是把上面的代理类模板化,用一个模板来实现代理类(主要用到了反射)

登录操作的动态代理

代理接口和被代理的对象都不变,需要修改的就是代理类

实现 InvocationHandler接口,重写invoke()方法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.text.SimpleDateFormat;
import java.util.Date;

public class DynamicLoginProxy implements InvocationHandler {
    private Object target;

    public DynamicLoginProxy(Object target) {
        this.target = target;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println(getTime());
        Object obj = method.invoke(target, args);
        System.out.println("登录成功");
        return obj;
    }
	/**
	 * 获得代理类对象
	 */
    public Object getProxy() {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(), this);
    }

    private String getTime() {
        Date date = new Date();
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        String time = sdf.format(date);
        return time;
    }
}

Test类

public class Test {

    public static void main(String[] args) {
        // 用于保存,生成的动态代理类的字节码文件com.sun.proxy;在idea中会在src目录的上方生成
 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
        User user = new User();
        // 获取代理
        DynamicLoginProxy dynamicLoginProxy = new DynamicLoginProxy(user);
        Object proxy = dynamicLoginProxy.getProxy();
        Login login = (Login) proxy;
        login.userLogin();
    }
}

动态代理就是在运行的过程中动态的生成一个代理类,用完就消失了

public final class $Proxy0 extends Proxy implements Login {
    //...
        public final void userLogin() throws  {
        try {
            super.h.invoke(this, m3, (Object[])null);
        } catch (RuntimeException | Error var2) {
            throw var2;
        } catch (Throwable var3) {
            throw new UndeclaredThrowableException(var3);
        }
    }
    //...
}

上面是部分代码,其中 super.h.invoke(...)就是Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);

posted @ 2021-11-08 19:19  gain&get  阅读(119)  评论(0)    收藏  举报