转载自:
https://www.cnblogs.com/bigbigtree/p/9217584.html
https://www.cnblogs.com/libinhyq/p/9578902.html
定义
代理模式顾名思义,作为某对象的代表,去做某些事情。例如海淘、转运公司,代收快递等,都是生活中的代理模式。
代理模式的英文叫做Proxy或Surrogate。
定义:代理(Proxy)是一种设计模式,为其他对象提供一个代理以控制对某个对象的访问,即通过代理对象访问目标对象。
这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能.
+ 这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法
代理模式的关键点:代理对象与目标对象.代理对象是对目标对象的扩展,并会调用目标对象
角色
代理模式包含如下角色:
Subject: 抽象角色
Proxy: 代理角色
RealSubject: 真实角色
应用场景
常见的代理有:
远程代理(Remote Proxy):对一个位于不同的地址空间对象提供一个局域代表对象,如RMI中的stub
虚拟代理(Virtual Proxy):根据需要将一个资源消耗很大或者比较复杂的对象,延迟加载,在真正需要的时候才创建
保护代理(Protect or Access Proxy):控制对一个对象的访问权限。
智能引用(Smart Reference Proxy):提供比目标对象额外的服务和功能。
静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类.
关键:在编译期确定代理对象,在程序运行前代理类的.class文件就已经存在了。
比如:在代理对象中实例化被代理对象或者将被代理对象传入代理对象的构造方法
例子
模拟保存动作,定义一个保存动作的接口:IUserDao.java,然后目标对象UserDao.java实现这个接口的方法,此时如果使用静态代理方式,就需要在代理对象(UserDaoProxy.java)中也实现IUserDao接口.调用的时候通过调用代理对象的方法来调用目标对象.
需要注意的是,代理对象与目标对象要实现相同的接口,然后通过调用相同的方法来调用目标对象的方法
接口:IUserDao.java
public interface IUserDao {
void save();
}
目标对象类:UserDao.java
public class UserDao implements IUserDao {
public void save() {
System.out.println("----已经保存数据!----");
}
}
代理对象:UserDaoProxy.java
public class UserDaoProxy implements IUserDao{
//接收保存目标对象
private IUserDao target;
public UserDaoProxy(IUserDao target){
this.target=target;
}
public void save() {
System.out.println("开始事务...");
target.save();//执行目标对象的方法
System.out.println("提交事务...");
}
}
测试类:App.java
public class App {
public static void main(String[] args) {
//目标对象
UserDao target = new UserDao();
//代理对象,把目标对象传给代理对象,建立代理关系
UserDaoProxy proxy = new UserDaoProxy(target);
proxy.save();//执行的是代理的方法
}
}
静态代理总结: 可以做到在不修改目标对象的功能前提下,对目标功能扩展.
缺点:代理类和委托类实现相同的接口,同时要实现相同的方法。这样就出现了大量的代码重复。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
1.定义
在代理类和被代理类之间加上一个事务处理器,将我们需要处理的具体功能放在其中进行处理。
InvocationHandler接口(事务处理器)中仅定义了一个方法public object invoke(Object obj,Method method,Object[] args),在实际使用中,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组,这个抽象方法在代理类中动态实现。
Proxy:该类即为动态代理类,通过newProxyInstance方法可以返回代理类的一个实例,返回后的代理类可以当做被代理类使用(可使用被代理类的在接口中声明过的方法)。
2.实现步骤
创建一个实现接口InvocationHandler的类,它必须实现invoke方法,在invoke方法中添加具体的业务逻辑。
创建被代理的类和接口。
调用Proxy的静态方法newProxyInstance,动态创建一个代理类。
通过代理调用方法。
3.示例
public interface Moveable {
void move();
}
public class Car implements Moveable {
@Override
public void move() {
//实现开车
try {
Thread.sleep(new Random().nextInt(1000));
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
public class TimeHandler implements InvocationHandler{
private Object target;
public TimeHandler(Object target) {
super();
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
long starttime = System.currentTimeMillis();
System.out.println("汽车开始行驶.......");
method.invoke(target);
long endtime = System.currentTimeMillis();
System.out.println("汽车结束行驶......");
System.out.println("汽车行驶时间:"+(endtime - starttime)+"毫秒!");
return null;
}
}
public class TestProxy {
public static void main(String[] args) {
Car car = new Car();
InvocationHandler h = new TimeHandler(car);
Class> cls = car.getClass();
/**
* loader 类加载器
* interfaces 实现接口
* h InvocationHandler
* */
Moveable m = (Moveable) Proxy.newProxyInstance(cls.getClassLoader(),
cls.getInterfaces(), h);
m.move();
}
}