xiaobenchi

导航

设计模式之结构型1

设计模式之结构型1

1. 代理模式

总的来说,根据代理类的创建时机和创建的方式不同,可以将代理分为静态代理和动态代理。

代理模式属于开闭原则的典型应用。

代理对象存在的价值主要用于拦截对真实业务对象的访问;

代理对象应该具有和目标对象相同的方法,即实现共同的接口或继承于同一个类;

代理对象应该是目标对象的增强。

代理模式包含如下几个角色:

  • 客户端:客户端面向接口编程,使用代理角色完成某项功能。
  • 抽象主题:一般实现为接口,是对(被代理对象的)行为的抽象。
  • 被代理角色(目标类):直接实现上述接口,是抽象主题的具体实现。
  • 代理角色(代理类):实现上述接口,是对被代理角色的增强。

1.1 静态代理

以电影院播放电影为例,核心接口功能是播放电影,但是电影院作为代理,还可以播放广告,出售零食。

  • 抽象主题(接口)

    public interface Movie{
        void play();
    }
    
  • 被代理角色(目标类)与代理角色(代理类)

    • 真正实现Movie接口的类
    public class RealMovie implements Movie{
        @override
        public void play(){
            System.out.println("您正在观看电影《哈利波特之凤凰社》");
        }
    }
    
    • 代理类
    package com.frank.test;
    
    public class Cinema implements Movie {
    
        RealMovie movie;
        public Cinema(RealMovie movie) {
            super();
            this.movie = movie;
        }
    
        @Override
        public void play() {
            guanggao(true);    // 代理类的增强处理
            movie.play();     // 代理类把具体业务委托给目标类,并没有直接实现
            guanggao(false);    // 代理类的增强处理
        }
    
        public void guanggao(boolean isStart){
            if ( isStart ) {
                System.out.println("电影马上开始了,爆米花、可乐、口香糖9.8折,快来买啊!");
            } else {
                System.out.println("电影马上结束了,爆米花、可乐、口香糖9.8折,买回家吃吧!");
            }
        }
    }
    
  • 客户端

    public class ProxyTest{
        public static void main(String[] args){
            RealMovie realmovie = new RealMovie();
            Movie movie = new Cinema(realmovie);
            movie.play();
        }
    }
    

1.2 动态代理

动态代理可以在程序运行期间,根据需要,动态地创建代理类及其实例来完成具体的功能。

  • 抽象主题(接口)

    public interface Subject{
        public void doSomething();
    }
    
  • 被代理角色

    我们要有一个真正的实现这个Subject接口的类,以便代理

    import class RealSubject implements Subject{
        public void doSomething(){
            System.out.println("call doSomething()");
        }
    }
    
  • 代理角色(代理类)与客户端

    动态代理中,代理类及其实例是程序自动生成的,因此我们不需要手动去创建代理类。在Java的动态代理机制中,InvocationHandler(Interface)接口和Proxy(class)类是实现我们动态代理所必须用到的。事实上,Proxy通过使用InvocationHandler对象生成具体的代理对象。

    import java.lang.reflect.InvocationHandler;
    import java.lang.reflect.Method;
    
    /**
    * Title: InvocationHandler的实现
    * Description:每个代理的实例都有一个与之关联的InvocationHandler
    * 实现类,如果代理方法被调用,那么代理便会通知和转发给内部的InvocationHandler
    */
    public class ProxyHandler implements InvocationHandler{
        
        private Object proxied; //被代理对象
        
        public ProxyHandler(Object proxied){
            this.proxied = proxied;
        }
        
        public Object invoke(Object proxy,Method,Object[] args) throws Throwable{
            //在转调具体目标对象之前,可以执行一些功能处理
            System.out.printn("前置增强处理:yoyoyo...");
            
            //在转调具体目标对象的方法(三要素:实例对象+实例方法+实例方法的参数)
            Object obj = method.invoke(proxied,args);
            
            //在转调具体目标对象之后,可以执行一些功能处理
            System.out.println("后置增强处理:hahaha...");
            
            return obj;
        }
    }
    
  • 创建代理对象

    在实现了InvocationHander接口后,我们就可以创建代理对象了。在Java的动态代理机制中,我们使用Proxy类的静态方法newProxyInstance创建代理对象

    import java.lang.reflect.Proxy;
    
    import cn.handler.ProxyHandler;
    import cn.impl.RealSubject;
    import cn.inter.Subject;
    
    public class Test{
        public static void main(String[] args){
            
            //真实对象real
            Subject real = new RealSubject();
            
            //生成real的代理对象
            Subject proxySubject = (Subject)Proxy.newProxyInstance(
            Subject.class.getClassLoader(),new Class[]{Subject.class}, new ProxyHandler(real));
            
            proxySubject.doSomething();
            System.out.println("代理对象的类型:"+proxySubject.getClass().getName());
            System.out.println("代理对象所在类的父类型:"+proxySubject.getClass().getGemericSuperclass());
            
        }
    }
    
  • JDK中的InvovationHandler接口与Proxy类

    • InvocationHandler接口

      每个代理的实例都有一个与之关联的InvocationHandler实现类,如果代理的方法被调用,那么代理便会通知和转发给内部的InvocationHandler实现类,由它决定处理。

      public interface InvovationHandler{
          public Object invoke(Object proxy,Method method,Object[] args)
              throws Throwable;
      }
      

      InvocationHandler中的invoke()方法决定了怎样处理代理传递过来的方法调用。

    • Proxy类

      JDK通过Proxy的静态方法newProxyInstance动态地创建代理,该方法的声明入下:

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

      事实上,Proxy动态产生的代理对象调用目标方法时,代理对象会调用InvocationHandler实现类,所以InvocationHandler是实际执行者。

原文

posted on 2022-07-21 10:56  小迟在努力  阅读(13)  评论(0编辑  收藏  举报