设计模式(十二)代理模式

1、定义:代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗来讲就是中介。

 

2、UML类图

 

 

 代理模式中的角色分析:

  • 抽象对象角色(AbstractObject):声明了目标对象和代理对象的共同接口,这样依赖在任何可以使用目标对象的地方都可以使用代理对象;
  • 目标对象角色(RealObject):定义了代理对象所代表的目标对象;
  • 代理对象角色(ProxyObject):代理对象内部含有目标对象的引用,从而可以在任何时候操作目标对象;代理对象提供一个与目标对象相同的接口,以便可以在任何时候替代目标对象。代理对象通常在客户端调用传递给目标对象之前或者之后,执行某个操作,而不是单纯的将调用传递给目标对象。

 

3、代理模式的场景

  • 中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口;
  • 开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。

 

4、代理模式的种类

  1. 静态代理;
  2. 动态代理;
  3. CGLIB代理。

 

5、静态代理

 实现原理:代理对象将客户端的调用委派给目标对象,在调用目标对象之前跟之后都可以执行特定的操作,一个目标对象对应一个代理对象。代理类在编译时期就已经确定。

 

 1 /**
 2  * @author it-小林
 3  * @desc 抽象对象角色
 4  * @date 2021年08月02日 20:35
 5  */
 6 public abstract class AbstractObject {
 7 
 8     /**
 9      * 定义操作
10      */
11     public abstract void operation();
12 }
 1 /**
 2  * @author it-小林
 3  * @desc  目标对象角色
 4  * @date 2021年08月02日 20:38
 5  */
 6 public class RealObject extends AbstractObject {
 7     @Override
 8     public void operation() {
 9         System.out.println("Do Something!");
10     }
11 }
 1 /**
 2  * @author it-小林
 3  * @desc
 4  * @date 2021年08月02日 20:40
 5  */
 6 public class ProxyObject extends AbstractObject{
 7     RealObject realObject = new RealObject();
 8 
 9     @Override
10     public void operation() {
11         //在调用目标对象之前
12         System.out.println("Before Do Something!");
13         realObject.operation();
14         //在调用目标对象之后
15         System.out.println("After Do Something");
16     }
17 }
 1 /**
 2  * @author it-小林
 3  * @desc 测试类
 4  * @date 2021年08月02日 20:42
 5  */
 6 public class Client {
 7     public static void main(String[] args) {
 8         AbstractObject abstractObject = new ProxyObject();
 9         abstractObject.operation();
10     }
11 }

 

 

总结

  • 可以做到不修改目标对象的前提下,扩展目标对象的功能;
  • 不足之处就是因为代理对象需要同目标对象实现同样的接口,所以会有很多的代理类,造成类过多;并且,一旦接口中增加方法,目标对象同代理对象都需要进行维护。

 

6、动态代理

动态代理主要有如下特点:

  • 代理对象不需要实现目标对象的接口;
  • 代理对象的生成,使用的是Java的API,动态的在内存中构件代理对象(这需要我们指定创建代理对象/目标对象的接口的类型);
  • 动态代理也叫做JDK代理、接口代理。

JDK中生成代理对象的API

代理类所在的包为:java.lang.reflect.Proxy

JDK实现代理只需要使用newProxyInstance方法,但是该方法需要接收三个参数,源码中的方法定义为:

1 public static Object newProxyInstance(ClassLoader loader,
2                                           Class<?>[] interfaces,
3                                           InvocationHandler h)
4         throws IllegalArgumentException
5 {
6     //......
7 }

注意,该方法在Proxy类中是静态方法,且接收的三个参数依次为:

  • ClassLoader loader:指定当前目标对象使用类加载器,获取加载器的方法是固定的。
  • Class<?>[] interfaces:目标对象实现的接口类型,使用泛型方式确认类型。
  • InvocationHandler h:事件处理。执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入。

 

/**
 * @author it-小林
 * @desc 目标对象接口
 * @date 2021年08月03日 8:58
 */
public interface IUserDao {
    void save();
}
 1 /**
 2  * @author it-小林
 3  * @desc   目标对象类
 4  * @date 2021年08月03日 8:59
 5  */
 6 public class UserDao implements IUserDao {
 7     @Override
 8     public void save() {
 9         System.out.println("---------已经保存数据-------");
10     }
11 }
 1 /**
 2  * @author it-小林
 3  * @desc 创建动态代理对象
 4  *       动态代理对象不需要实现接口,但是需要指定接口类型
 5  * @date 2021年08月03日 9:03
 6  */
 7 public class ProxyFactory {
 8     //维护一个目标对象
 9     private Object target;
10     //对象构造时,提供目标对象
11     public ProxyFactory(Object target) {
12         this.target = target;
13     }
14 
15     //给目标对象生成代理对象
16     public Object getProxyInstance(){
17         return Proxy.newProxyInstance(
18                 target.getClass().getClassLoader(),
19                 target.getClass().getInterfaces(),
20                 new InvocationHandler() {
21                     @Override
22                     public Object invoke(
23                             Object proxy,
24                             Method method,
25                             Object[] args) throws Throwable {
26                         System.out.println("Begin Transaction");
27                         //执行目标对象方法
28                         Object returnValue = method.invoke(target, args);
29                         System.out.println("Commit Transaction");
30                         return returnValue;
31                     }
32                 }
33         );
34     }
35 }
 1 /**
 2  * @author it-小林
 3  * @desc 测试类
 4  * @date 2021年08月03日 9:10
 5  */
 6 public class Client {
 7     public static void main(String[] args) {
 8         //目标对象
 9         IUserDao userDao = new UserDao();
10         //原始类型
11         System.out.println(userDao.getClass());
12 
13         //给定目标对象。动态创建代理对象
14         IUserDao proxy = (IUserDao) new ProxyFactory(userDao).getProxyInstance();
15         //代理对象类型
16         System.out.println(proxy.getClass());
17         proxy.save();
18     }
19 }

 

posted @ 2021-08-03 09:37  it-小林  阅读(54)  评论(0编辑  收藏  举报