在某种情况下,A对象不方便或者不能直接引用B对象时,可以创建一个代理提供给A对象,来控制对B对象的访问。
让我们用示例来演示代理模式的应用。
示例场景:
water对象可以被喝掉,它提供一个drink()方法,现在提供一个WaterProxy代理,由这个代理去执行drink()的动作。
在这种简单的场景下为什么还要写代理呢?
因为假如water对象有其他拓展性的功能,又不想给外部调用,由代理去做的话,外部就只能间接的调用drink()方法,这也起到了对water对象的保护作用。
创建一个Drink接口:
package com.cc.proxy;
/**
* 代理类和被代理类需要共同实现的接口
* @author cc
* @date 21-12-18 18:05
*/
public interface Drink {
void drink();
}
然后是water对象:
package com.cc.proxy;
/**
* water对象
* @author cc
* @date 21-12-18 21:49
*/
public class Water implements Drink {
@Override
public void drink() {
System.out.println("drink water");
}
}
现在创建一个WaterProxy代理:
package com.cc.proxy;
/**
* water代理
* @author cc
* @date 21-12-18 21:50
*/
public class WaterProxy implements Drink {
private Water water;
@Override
public void drink() {
// 这里只是模拟场景,不考虑高并发的情况
if (water == null) {
water = new Water();
}
water.drink();
}
public Water getWater() {
return water;
}
public void setWater(Water water) {
this.water = water;
}
}
测试一下:
package com.cc.proxy;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
WaterProxy waterProxy = new WaterProxy();
waterProxy.drink();
}
}
结果:
drink water
可以看到,drink()的动作由WaterProxy代理去执行,调用者不知道被代理的对象是water,代理在这个过程中起到了中介的作用。
优点(摘自百度百科):
- 职责清晰,被代理的对象如示例中的water只需要关心自己的业务,通过将自身的部分功能提供给外部代理,让代理去完成一个业务,这使得各自的工作职责清晰,代码也显得简洁
- 代理对象作为中间者,可以起到保护被代理对象的作用
- 拓展性高
不足:一个Water对象需要有一个WaterProxy代理,现在我们新增了一个Milk对象,有需要有一个MilkProxy代理,这使得我们的代理类变多,并且这些代理类负责的工作都是一样的。还好,Java有动态代理。
静态代理和动态代理
上面的例子中,water对象的代理类需要提前写好,这种就叫做静态代理。在静态代理中,新增milk对象就要新增新的代理类,当我们的业务庞大起来后,代理类的部分也会继续庞大起来。
像water、milk又或者Coffee,他们的代理类做的工作都是一样的,既然如此,我们可以用Java提供的java.lang.reflect.Proxy类去动态生成代理对象,减少这些重复的代理对象类的编写,这种就叫动态代理。
示例代码
创建一个实现了InvocationHandler接口的实现类:
package com.cc.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class CommonInvocationHandler implements InvocationHandler {
// 被代理的对象
private Object proxied;
public CommonInvocationHandler(Object proxied) {
this.proxied = proxied;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在调用被代理对象的方法前做一些事情
System.out.println("before doing something");
// 调用被代理对象的方法
Object result = method.invoke(proxied, args);
// 在调用被代理对象的方法后做一些事情
System.out.println("after doing something");
return result;
}
}
新增一个Milk对象来增强演示效果:
package com.cc.proxy;
/**
* milk对象
* @author cc
* @date 21-12-18 22:07
*/
public class Milk implements Drink {
@Override
public void drink() {
System.out.println("drink milk");
}
}
测试一下:
package com.cc.proxy;
import java.lang.reflect.Proxy;
public class Main {
public static void main(String[] args) {
{
Water water = new Water();
Drink proxy = (Drink) Proxy.newProxyInstance(water.getClass().getClassLoader(), water.getClass().getInterfaces(), new CommonInvocationHandler(water));
proxy.drink();
}
{
Milk milk = new Milk();
Drink proxy = (Drink) Proxy.newProxyInstance(milk.getClass().getClassLoader(), milk.getClass().getInterfaces(), new CommonInvocationHandler(milk));
proxy.drink();
}
}
}
结果:
before doing something
drink water
after doging something
before doing something
drink milk
after doging something
可以看到,我们不再需要创建像WaterProxy、MilkProxy这样功能重复的代理类,全部都是动态生成的。