代理模式
代理模式
代理就是把事情交给别人做,虽然自己能做
常见的代理就是租房
租客------------>租房
中介------------>租房
中介是专门租房的,对市场了解,我们可以把租房这件事交给中介去做,这样就可以减轻我们的负担
交给专门做租房这一件事的人去做
(在很多方法执行前后都有相同或相似的操作时,我们就可以有一个代理类,让他去处理,这样就不用每个类当中一个一个的写方法了)
这就是单一职责原则(一个类或者方法只做一件事)
静态代理
租房
通过静态代理的方式实现 中介租房
租客(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);

浙公网安备 33010602011771号