代理模式

代理模式

 给某一个对象提供一个代理对象,并由代理对象控制原对象的引用。

 有些时候,一个客户不想或者不能直接引用一个对象,可以通过代理对象在客户端和目标对象之前起到中介作用。代理模式的角色:

1.抽象对象角色

声明了目标对象和代理对象共同的接口,这样一来在任何可以使用目标对象的地方都可以使用代理对象。

2.目标对象角色

定义了代理对象所代表的目标对象

3.代理对象角色

代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象,代理对象提供一个目标对象相同的接口,以便可以在任何时候替代目标对象。

静态代理实例

假如一个接口里面有一个方法,想在调用这个接口的前后加东西,就可以使用代理模式。静态代理是代理模式最简单的实现,定义一个静态代理接口

1 public interface StaticHelloWorld {
2     void print();
3

实现类

1 public class StaticHelloWorldImpl implements StaticHelloWorld{
2 
3     @Override
4     public void print() {
5         System.out.println("hello world");
6     }
7 
8

代理对象,重点在于代理对象和实际对象实现的是同一个接口,希望在任何时候让代理对象替代实际对象

 1 public class StaticProxy implements StaticHelloWorld{
 2     
 3     private StaticHelloWorldImpl staticHelloWorldImpl;
 4     
 5     public StaticProxy(){
 6         if(staticHelloWorldImpl == null){
 7             staticHelloWorldImpl = new StaticHelloWorldImpl();
 8         }
 9     }
10     
11     public void print() {
12         System.out.println("before HelloWorld");
13         staticHelloWorldImpl.print();
14         System.out.println("after HelloWorld");
15     }
16 
17 }

main

1 public static void main(String[] args) {
2         StaticProxy proxy = new StaticProxy();
3         proxy.print();
4     }

结果是

1 before HelloWorld
2 hello world
3 after HelloWorld

静态代理的缺点

静态代理的特点是静态代理的代理类是程序员创建的,程序运行前静态代理的.class文件已经存在了。这种模式在代理量比较小时还可以,但是代理量大了就有很大的缺点:

1.代理内容无法复用,如果想换一种代理内容,比如在helloworld前后不想输入before和after..,想输出别的东西,那么就必须重新写一个代理对象。这样容易造成代理对象的膨胀。

2.接口里面新增了一个方法,实际对象实现了这个方法,代理对象也必须新增内容,去给这个新增方法增加代理内容。

动态代理实例

动态代理接口

1 public interface DynamicHelloWorld {
2     String print();
3 }

动态代理接口的实现

1 public class DynamicHelloWorldImpl implements DynamicHelloWorld{
2 
3     public String print() {
4         System.out.println("hello world");
5         return "DynamicHelloWorldImpl";
6     }
7 
8 }

动态代理类,在java中动态代理需要实现InvocationHandler接口。该接口只有一个invoke方法。

第一种

 1 public class DynamicProxy implements InvocationHandler
 2 {
 3     private Object target;
 4     
 5     public Object newInstance(Object target)
 6     {
 7         this.target = target;
 8         
 9         return Proxy.newProxyInstance(target.getClass().getClassLoader(), 
10                 target.getClass().getInterfaces(), this);
11     }
12     
13     public Object invoke(Object proxy, Method method, Object[] args)
14             throws Throwable
15     {
16         System.out.println("Before DynamicProxy");
17         method.invoke(target, args);
18         System.out.println("After DynamicProxy");
19         return null;
20     }
21 }

第二种 

 1 public class DynamicProxy implements InvocationHandler
 2 {
 3     private Object target;
 4     
 5     public DynamicProxy(Object target)
 6     {
 7         this.target = target;
 8     }
 9     
10     public Object invoke(Object proxy, Method method, Object[] args)
11             throws Throwable
12     {
13         System.out.println("Before DynamicProxy");
14         method.invoke(target, args);
15         System.out.println("After DynamicProxy");
16         return null;
17     }
18 }

第一种main函数

 1 public class DynamicTestMain
 2 {
 3     public static void main(String[] args) throws Exception
 4     {
 5         DynamicProxy dp = new DynamicProxy();
 6         DynamicHelloWorld dhwi = new DynamicHelloWorldImpl();
 7         DynamicHelloWorld dhw = (DynamicHelloWorld)dp.newInstance(dhwi);
 8         dhw.print();
 9     }
10 }

第二种main函数

 1 public class DynamicTestMain
 2 {
 3     public static void main(String[] args) throws Exception
 4     {
 5         DynamicHelloWorld dhwi = new DynamicHelloWorldImpl();
 6         InvocationHandler ih = new DynamicProxy(dhwi);
 7         DynamicHelloWorld dhw = 
 8                 (DynamicHelloWorld)Proxy.
 9                 newProxyInstance(DynamicHelloWorld.class.getClassLoader(), 
10                                  new Class<?>[]{DynamicHelloWorld.class}, ih);
11         dhw.print();
12     }
13 }

不管哪种写法,运行结果都是一样的:

Before DynamicProxy
Enter DynamicHelloWorldImpl.print()
After DynamicProxy

 动态代理,利用动态编译+反射技术,把实际对象的方法调用转换成对传入的InvocationHandler接口实现类的invoke方法的调用。

动态代理的优缺点

优点:

1.类少了

2.代理内容的实现类可以复用,可以给A接口用,也可以给B接口用。

缺点:

只能针对于接口生成代理,不能针对一个类生成代理。如果想要为某一个单独的类实现一个代理可以考虑GGLIB技术。

原文地址:https://www.cnblogs.com/tp123/p/6497139.html