zoukankan      html  css  js  c++  java
  • 设计模式(十二)代理模式

    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 }
    如本文有侵权行为,请及时与本人联系,多多包涵! 小生初出茅庐,多多指教!

    本文来自博客园,作者:it-小林,转载请注明原文链接:https://www.cnblogs.com/linruitao/p/15067834.html

  • 相关阅读:
    sed命令
    python常用库
    python标准库
    从 Python 打包到 CLI 工具
    pip
    python包自我理解
    docker常用命令
    chattr命令
    xmss
    live2d-widget.js
  • 原文地址:https://www.cnblogs.com/linruitao/p/15067834.html
Copyright © 2011-2022 走看看