zoukankan      html  css  js  c++  java
  • 设计模式之代理模式

    代理模式(Proxy Pattern

    为其他对象提供一种代理以控制对这个对象的访问。
    Provide a surrogate or placeholder for another object to control access to it.

     

    代理模式的本质:
      代理类和被代理类需要实现同一个接口,这样他们有共同的函数。函数真正的实现在被代理类中完成,代理类的每一个函数仅仅是调用了被代理类的对应的函数。

    个人理解:

           代理模式将原类进行封装,客户端不能直接找到原类,必须通过代理角色。即代理是原类的一个替身,客户端要找原类,统统找代理就可以搞定。明星和经纪人就是一种代理模式。

    角色定义:

    ● Subject 抽象主题角色
         抽象主题类可以是抽象类也可以是接口,是一个最普通的业务类型定义,无特殊要求。

    ● Real Subject 具体主题角色

        也叫做被委托角色、被代理角色。它才是冤大头,是业务逻辑的具体执行者

    ● Proxy代理主题角色
        也叫做委托类、代理类。它负责对真实角色的应用,把所有抽象主题类定义的方法限制委托给真实主题角色实现,并且在真实主题角色处理完毕前后做预处理和善后处理工作

    通用源代码

    //抽象类
    public interface Subject {
         //定义一个方法
         public void request();
    //被代理
    public class RealSubject implements Subject {
         //实现方法
         public void request() {
                 //业务逻辑处理
         }
    }
    //代理类
    public
    class Proxy implements Subject { //要代理哪个实现类 private Subject subject = null; //默认被代理者 public Proxy(){ this.subject = new Proxy(); } //通过构造函数传递代理者 public Proxy(Object...objects ) { } //实现接口中定义的方法 public void request() { this.before(); this.subject.request(); this.after(); } //预处理 private void before(){ //do something } //善后处理 private void after(){ //do something } }

    实例代码

    //明星接口
    public interface IStar {
         //明星都会签名
         public void sign();
    }
    //明星只有一个行为:签字。我们来看明星的实现,如代码清单3
     
    //明星
    public class Singer implements IStar {
         public void sign() {
                 System.out.println("明星签字:我是XXX大明星");
         }
    }
     
     
    //经纪人与明星应该有相同的行为,比如说签名,虽然经纪人不签名,但是他把你要签名的笔记本、衣服、CD等传递过去让真正的明星签字,
     
    //经纪人
    public class Agent implements IStar {
         //定义是谁的经纪人
         private IStar star;
         //构造函数传递明星
         public Agent(IStar _star){
                 this.star = _star;
         }
         //经纪人是不会签字的,签字了歌迷也不认
         public void sign() {
                 star.sign();
         }
    }
    //追星族
    public class Idolater {
         public static void main(String[] args) {
                 //崇拜的明星是谁
                 IStar star = new Singer();
                 //找到明星的经纪人
                 IStar agent = new Agent(star);
                 System.out.println("追星族:我是你的崇拜者,请签名!");
                 //签字
                 agent.sign();
         }
    }

    运行结果:

    追星族:我是你的崇拜者,请签名!
    明星签字:我是XXX大明星

    看看我们的程序逻辑,我们是找明星的经纪人签字,真实签字的是明星,经纪人只是把这个请求传递给明星处理而已,这是普通的代理模式的典型应用。

    代理模式的扩展

    普通代理、强制代理、动态代理

    1)普通代理:要求客户端只能访问代理角色,而不能访问真实角色。

              在该模式下,调用者只知道代理而不知道真是的角色是谁,屏蔽了真是角色的变更对高层模块的影响,真实的主题角色想怎么修改都可以。在实际项目中,一般通过约定来禁止new一个真实的角色。

    2)强制代理:客户端必须通过真实角色查找到代理角色,否则你不能访问。

    就好比是你和一个明星比较熟,相互认识,有件事情你需要向她确认一下,于是你就直接拨通了明星的电话:
                      “喂,大明星啊,我要见一下×××导演,你帮下忙了!”
                     “不行呀衰哥,我这几天很忙呀,你找我的经纪人吧……”

    郁闷了吧,你是想直接绕过她的代理,谁知道返回的还是她的代理,这就是强制代理,你可以不用知道代理存在,但是你的所作所为还是需要代理为你提供。

    3)动态代理:

         在实现阶段不用关心代理谁,而在运行阶段才指定代理哪一个对象。相对来说,自己写代理类的方式就是静态代理。

    基于JDK的动态代理 

    //接口
    public interface Person {
        
        public void eat();
    
    }
    //被代理类(目标类)
    public class PersonImpl implements Person {
    
        @Override
        public void eat() {
             System.out.println("吃午饭");
        }
    
    }

    //调用处理器
    public class PersonInvocationHandler implements InvocationHandler {
    
        private Object obj;
    
        public PersonInvocationHandler(Object obj) {
            this.obj = obj;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("吃早饭");
            method.invoke(obj, args);
            System.out.println("吃完饭");
            return null;
        }
    
    }

     有一个类叫Proxy,来看JDK描述,我们主要使用了newProxyInstance( )的静态方法。

    //测试Demo
    public class JdkTest {
    
        public static void main(String[] args) throws Exception {
            PersonInvocationHandler personInvocationHandler = new PersonInvocationHandler(new PersonImpl());
            
            //利用JDK的Proxy类的newProxyInstance方法创建代理对象(代理类),该方法需要三个参数:1)目标类 的 类加载器;2)目标类 所实现的所有接口; 3)重写了invoke方法的InvocationHandler类)
            Person personProxy = (Person) Proxy.newProxyInstance(
                    PersonImpl.class.getClassLoader(),
                    PersonImpl.class.getInterfaces(), 
                    personInvocationHandler);
            
            personProxy.eat();
        }
    }

    运行结果:

       其中invoke方法是接口Invocation Handler定义必须实现的,它完成对真实方法的调用。我们来详细讲解一下Invocation Handler接口,动态代理是根据被代理的接口生成所有的方法,也就是说给定一个接口,动态代理会宣称“我已经实现该接口下的所有方法了”,那各位读者想想看,动态代理怎么才能实现被代理接口中的方法呢?默认情况下所有的方法返回值都是空的,是的,代理已经实现它了,但是没有任何的逻辑含义,那怎么办?好办,通过Invocation Handler接口,所有方法都由该Handler来进行处理,即所有被代理的方法都由Invocation Handler接管实际的处理任务。

    参考:

    《设计模式之禅》(强烈推荐)

    https://blog.csdn.net/qq_25827845/article/details/52452953

  • 相关阅读:
    Jmeter——关联与正则
    Jmeter图形插件扩展
    Jmeter——检查点
    Jmeter——集合点
    OpenGL帧缓存对象(FBO:Frame Buffer Object)(转载)
    unicode 和 utf8
    管理node的版本
    pyqt5 开发环境
    cmake
    一些可能常用的工具函数
  • 原文地址:https://www.cnblogs.com/xdyixia/p/9265233.html
Copyright © 2011-2022 走看看