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

  • 相关阅读:
    caffe常用层: batchNorm层和scale层
    简述configure、pkg-config、pkg_config_path三者的关系
    python删除list中元素的三种方法
    Leetcode 872. Leaf-Similar Trees
    Leetcode 508. Most Frequent Subtree Sum
    Leetcode 572. Subtree of Another Tree
    Leetcode 894. All Possible Full Binary Trees
    Leetcode 814. Binary Tree Pruning
    Leetcode 557. Reverse Words in a String III
    python 多维list声明时的小问题
  • 原文地址:https://www.cnblogs.com/linruitao/p/15067834.html
Copyright © 2011-2022 走看看