class ExecutePerson implements Shopping {
private String name;
public ExecutePerson(String name) {
this.name = name;
}
}
class ProxyPerson implements Shopping {
private ExecutePerson ep;
public ProxyPerson(ExecutePerson ep) {
this.ep = ep;
}
@Override
public void buyFood() {
ep.buyFood();
}
}
public class ProxyTest {
public static void main(String[] args) {
String name = "李四";
Shopping shopping = new ProxyPerson(new ExecutePerson(name));
shopping.buyFood();
}
}
李四 买东西
在使用静态代理实现该功能之后,我们发现实现起来很简单,通过一个代理类就可以在不影响目标对象的前提进行扩展使用。但是我们也发现一个问题,如果我们不确定需要代理某个真实类的时候会比较麻烦,而且在类过多的时候,目标对象与代理对象都要维护,会使系统复杂度提升,维护起来也更加麻烦。 不过这时我们就可以使用`动态代理`来进行解决。 ### 动态代理 所谓`动态代理`可以不必强行指定某个真实的角色,只需要在运行时决定就可以了。这里我们可以使用JDK中`java.lang.reflect`来进行开发。 JDK对动态代理提供了以下支持: - java.lang.reflect.Proxy 动态生成代理类和对象 - java.lang.reflect.InvocationHandler - 可以通过invoke方法实现对真实角色的代理访问; - 每次通过Proxy生成代理类对象时都要指定对象的处理器对象. 那么废话不在多说,开始进行代码改造,之前的接口和真实者不需要更改,我们只需要更改代理者就可以了。 更改之后的代码如下:class ProxyPerson2 implements InvocationHandler {
private Shopping shopping;
private final String methodName = "buyFood";
public ProxyPerson2(Shopping shopping) {
this.shopping = shopping;
}
}
测试代码,注意这里调用和之前不同! 这里通过Proxy类中的newProxyInstance方法会动态生成一个代理类,然后进行调用。其中这三个参数的说明如下: - ClassLoader: 生成一个类, 这个类也需要加载到方法区中, 因此需要指定ClassLoader来加载该类 - Class[] interfaces: 要实现的接口 - InvocationHandler: 调用处理器public class ProxyTest {
public static void main(String[] args) {
Shopping shopping2 = (Shopping)Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(), new Class[]{Shopping.class}, new ProxyPerson2(new ExecutePerson(name)));
shopping2.buyFood();
}
}
```
代理模式优点:
1、职责清晰。 2、高扩展性。 3、智能化。
代理模式缺点:
1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。
注意事项: