• 模糊的概念(2)


    这种概念的模糊,还是因为当时在看书或者学习某一个知识点的时候,没有能够把这个知识变为自己的东西,停留在比较浅层次的理解的基础上面,没有能够真正的运用上面,就像那些笑话中所说的一样,“这些道理臣妾都明白,可就是过不好日子”。道理光是明白肯定是过不好日子的,明白了,理解了,最重要的是想办法去应用,把学到的知识最终归到自己的知识体系里面,这样才算是真正的明白,才有过好日子的可能。

    继续说设计模式:代理的设计模式,以前的理解,比较的高效,认为代理就是请求来临的时候,代理对象首先执行,然后在去执行被代理对象的方法。如果按照这种大而化之的理解,那么组合类里面的任何一个调用都是代理模式了。

    还是首先是简单的UML:

    latex-table

    真正的对象和代理对象都会实现这个接口,然后在调用的时候,调用的是代理的对象,然后代理的对象再去调用真正的对象。

    // 抽象角色:
    abstract public class Subject {
        abstract public void  request();
    }
    
    // 真实角色:实现了Subject的request()方法
    public class  RealSubject  extends  Subject  {
      public  RealSubject()  { }
    
      public void  request()  {
         System.out.println( " From real subject. " );
        }
    }
    
    // 代理角色:
    public class  ProxySubject  extends  Subject  {
      // 以真实角色作为代理角色的属性
      private  Subject realSubject;
    
      public  ProxySubject(Subject realSubject)  {this.realSubject = realSubject }
    
      // 该方法封装了真实对象的request方法
      public void  request()  {
         preRequest();
         realSubject.request();  // 此处执行真实对象的request方法
         postRequest();
      }
      ...
    }
    
    // 客户端调用:
    RealSubject real = new RealSubject();
    Subject sub = new  ProxySubject(real);
    Sub.request();

    还有一种方式是继承的方式:

    image

    核心的代码是:

    //dosomething before
        super.doOperation()  
       //dosomething after

    1. 采用父类的调用,不用接口的这种方式。

    一般的情况下,真是的对象应该增加访问的限制,例如:不能够在外部的访问。

    说到了代理模式,JDK实现了一个动态代理的模式,为什么会有这个动态代理,因为上面虽然实现了代理,但是每一个类一个代理的话,代码呈现臃肿,并且也不符合同一个功能对应一块或者一个类,或者说抽象封装的设计理念,所以就有了JDK的动态代理,其UML是:

    image

    具体的代码:

    package regularExpression.current;
    
    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    import java.lang.reflect.Proxy;
    
    interface ISubject {
        public void showName(String name);
    }
    
    class RealSubject implements ISubject {
    
        @Override
        public void showName(String name) {
            System.out.println(name+"闪亮登场");
        }
    
    }
    
    class LogHandler implements InvocationHandler {
    
        Object target=null;
        
        public Object getTarget() {
            return target;
        }
    
        public void setTarget(Object target) {
            this.target = target;
        }
    
        @Override
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            Object result=null;
            //调用目标对象方法前的逻辑
            System.out.println("下面有一个大人物要出现");
            //调用目标对象的方法,这句代码将代理与目标类联系了起来
            method.invoke(target, args);
            //调用目标对象方法后的逻辑
            System.out.println("大家鼓掌欢迎");
            return result;
                    
        }
    
    }
    public class Client {
        /**
         * @param args
         */
        public static void main(String[] args) {
            
            LogHandler logHandler=new LogHandler();
            logHandler.setTarget(new RealSubject());
            //创建代理对象
            ISubject proxySubject=(ISubject)Proxy.newProxyInstance(RealSubject.class.getClassLoader(), RealSubject.class.getInterfaces(), logHandler);
            System.out.println("-------JDK Proxy-------------");
            proxySubject.showName("委座");
    
        }
    
    }

    看到这个方法:java.lang.reflect.Proxy.newProxyInstance(ClassLoader, Class<?>[], InvocationHandler) 应该能够推出来:

    JDK的动态代理,必须的要实现了接口的类才能够有动态代理,不然的话,在类Proxy的方法:

    public static Object newProxyInstance(ClassLoader loader,
                                              Class<?>[] interfaces,
                                              InvocationHandler h)
            throws IllegalArgumentException

    无法建立代理的实例,就无法代理了,但是cglib可以,具体的UML为:

    image

    可以看到的是RealSubject 不需要实现一个接口,

    class LogIntercept implements MethodInterceptor {
        Object target=null;
        
        public Object getTarget() {
            return target;
        }
    
        public void setTarget(Object target) {
            this.target = target;
        }
        
        @Override
        public Object intercept(Object arg0, Method arg1, Object[] arg2,
                MethodProxy arg3) throws Throwable {
            
            Object result=null;
            //调用目标对象方法前的逻辑
            System.out.println("下面有一个大人物要出现");
            //调用目标对象的方法,这句代码将代理与目标类联系了起来
            arg3.invoke(target, arg2);
            //调用目标对象方法后的逻辑
            System.out.println("大家鼓掌欢迎");
            return result;
        }
    
    }

    调用的方式:

    LogIntercept logIntercept=new LogIntercept();  
            logIntercept.setTarget(new RealSubject());        
            RealSubject proxySubject1=(RealSubject )Enhancer.create(RealSubject.class, logIntercept); 
            System.out.println("-------CBLIB-------------");  
            proxySubject1.showName("委座");

    这也就能够理解spring提供两种代理方式的原因:

    目标对象有没有实现接口Spring都会选择使用CGLIB代理。所以在默认情况下,如果一个目标对象如果实现了接口,Spring则会选择JDK动态代理策略动态的创建一个接口实现类(动态代理类)来代理目标对象,可以通俗的理解这个动态代理类是目标对象的另外一个版本,所以这两者之间在强制转换的时候会抛出j ava.lang.ClassCastException。而所以在默认情况下,如果目标对象没有实现任何接口,Spring会选择CGLIB代理, 其生成的动态代理对象是目标类的子类。

    代理模式这样算是到一个阶段,这样才能够穿起来,理清一个点。

  • 相关阅读:
    代码写界面的工厂类
    Masonry的一些等间距布局
    开发中的小细节随记
    ios7 实现应用内保真截屏
    利用GCD实现单利模式的宏代码
    AVAudioPlayer的锁屏播放控制和锁屏播放信息显示
    NSXMLParser自定义的一个xml解析工具
    利用NSURLSession完成的断点续传功能
    AVFoundation下的视频分帧处理
    Redis自学笔记:4.2进阶-过期时间
  • 原文地址:https://www.cnblogs.com/zhailzh/p/4163150.html
Copyright © 2020-2023  润新知