• 代理模式


    在某些情况下,一个对象不适合或者不能直接引用另一个对象,可以定义一个类作为调用另外一个类的中介, 类似于生活中的律师,票贩子 这就是代理类

    或者需要对目标对象的方法进行一些增强,但是不能直接修改目标类,因为这违反了开闭原则

    概念:

    抽象角色(抽象主题):真实角色和代理角色的共同实现的接口
    真实角色(真实主题): 代理角色所代理的真实角色,是我们最终要引用的对象
    代理角色(代理主题):代理角色内部含有对真实角色的引用。代理角色可以在执行真实角色操作时,附加其他的操作;相当于对真实角色进行封装。

    分类:
    静态代理:在程序运行前代理和被代理对象在代理之前是确定的。

    静态代理有两种实现方式:

    继承: 代理类 继承父类 重写父类的方法 

    聚和:代理类和目标类必须实现同一个接口 代理类有目标类的对象属性,重写接口的方法时 可以通过目标类对象属性调用目标类方法

    -----------------------------------------------------------------------------------------------

    动态代理:在程序运行前事先并不知道真实的角色。
    CGLIB动态代理:不需要实现接口,因其使用的是继承
    JDK动态代理: 真实角色必须实现接口

    ---------------------------------------

    接下来演示静态代理

    新建一个接口

    public interface TrainStationDao { //火车站接口
        void Buytickets();//购票方法
        
    }

     建这个接口的实现类

    public class TrainStationImpl implements TrainStationDao {
    
        public void Buytickets() {
        System.out.println("购票中............");
        System.out.println("购票成功");
        }
    
    }

    这样就实现了火车站购票方法  但是如果我想拓展成为在火车票代售点购买火车票呢

    新建一个代理类

    public class TrainStationImplProxy extends TrainStationImpl {
       //使用继承的方式 实现静态代理
        
        @Override
        public void Buytickets() {
            System.out.println("火车票代售点");
            super.Buytickets();
        }
    }

    这个类继承了TrainStationImpl类 并且重写了父类中的Buytickets()方法 也就是购票方法  新增了火车票代售点功能  然后在调用父类的方法

    测试代码

    public static void main(String[] args) {
            TrainStationDao trainStation=new TrainStationImplProxy();
            //因为代理类继承了TrainStationImpl类 间接也就是实现了TrainStationDao接口,这是向上转型 是安全的
     trainStation.Buytickets(); }

    输出结果

    火车票代售点
    购票中............
    购票成功

    接下来用聚合的方式实现静态代理

    新建一个接口

    public interface AirportDao {//飞机场接口
        void Buytickets();//购票方法
    }

    新建一个实现类

    public class AirportDaoImpl implements AirportDao {
    
        public void Buytickets() {
            System.out.println("购票中.........");
            System.out.println("购票成功");
    
        }
    
    }

    这里也想改成在飞机票代售点购票

    新建一个代理类

    public class AirportDaoImplProxy implements AirportDao {
        //使用聚合的方式 实现静态代理
        
        private AirportDao airportDao; //目标类的对象属性
    public void Buytickets() { //也实现了和目标类相同的接口 重写目标类也有的方法 System.out.println("飞机票代售点"); airportDao.Buytickets(); //通过目标类对象属性调用目标类中相同的方法 } public AirportDaoImplProxy(AirportDao airportDao) { //有参构造方法 将传入的目标对象,设置为类中目标对象属性的值 super(); this.airportDao = airportDao; } }

    测试代码

    public class Test {
        public static void main(String[] args) {
        
            AirportDao airportDao=new AirportDaoImplProxy(new AirportDaoImpl());
        
            airportDao.Buytickets();
        }
    
    }

    输出结果

    飞机票代售点
    购票中.........
    购票成功

    总结起来就是 

    继承就是代理类去继承目标类 并重写目标类想要调用的方法,在重写方法内部 就可以调用父类的方法 并且也可以新增新的功能

    聚合就是代理类实现目标类实现的接口 然后定义一个属性 为目标类对象,通过有参构造方法给这个属性赋值,重写接口定义的方法,通过目标对象属性就能调用目标类的方法

    但是静态代理有很大的弊端 比如我有一个类想要拓展 就要新建一个代理类 不方便 会有很多类 所以一般使用动态代理

    动态代理

     定义一个动态代理类

    public class TrainStationImplJDKProxy implements InvocationHandler {
       private Object target;//目标类的对象
        
        
        public Object newInstance(Object targetClassObject){//创建代理对象方法
            this.target=targetClassObject;//将传入的目标类对象,赋值给代理类的属性目标对象
            return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
            //通过Proxy的静态方法newProxyInstance(参数1:目标类的类加载器,参数2:目标类实现的接口Class对象数组,参数3:这个代理类自身);
        }
        
        //执行目标类的方法 并且可以拓展一些新的功能  参数1:代理类对象,参数2:要执行的方法对象,参数3:方法执行所需要的参数
        public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
            System.out.println("火车票代售点");//这是我拓展的新的功能
            return    method.invoke(target, args);
    //使用方法对象的invoke()方法 传入目标对象 和参数 相当于调用目标类的对应方法,并将原有的方法返回值 返回
        }
    
    }

    测试代码

    public class Test2 {
        public static void main(String[] args) {
        TrainStationDao trainStationDao=(TrainStationDao)new TrainStationImplJDKProxy().newInstance(new TrainStationImpl());    
    
        trainStationDao.Buytickets();
       
        
        }
    
    }

    输出结果还是与之前静态代理的结果一样 我就不写了

    这是使用jdk的动态代理,

    代理类要实现InvocationHandler接口 重写invoke()方法  然后通过Proxy类的静态方法newProxyInstance()方法返回一个代理类的实例

    是基于接口的 也就是目标类必须实现了接口 如果没有实现 那么jdk动态代理无法生成

    可以使用Cglib来生成代理类  这个是基于类来生成 也就是继承目标类的方式  接下来演示

    public class AirportDaoImplCglibProxy implements MethodInterceptor {
        private Object target;//目标类的对象
    
    
        public Object newInstance(Object targetClassObject){//创建代理对象方法
            this.target=targetClassObject;//将传入的目标类对象,赋值给代理类的属性目标对象
            Enhancer enhancer=new Enhancer();
            enhancer.setSuperclass(target.getClass());//设置代理类的父类 ,也就是目标类
            enhancer.setCallback(this);//设置回调
            return enhancer.create();//创建代理对象 并返回
        }
        
        
        
        public Object intercept(Object arg0, Method arg1, Object[] args,
                MethodProxy methodProxy) throws Throwable {
            System.out.println("飞机票代售点");//这是我拓展的新的功能
            
            return methodProxy.invoke(target, args);
            //使用方法代理对象的invoke()方法 传入目标对象 和参数 相当于调用目标类的对应方法,并将原有的方法返回值 返回
        }
         
    }

    Cglib和JDK实现还是很相似的

    实现MethodInterceptor接口 重写intercept()方法  然后使用Enhancer类的方法,设置代理类的父类 设置回调 和创建代理对象

    测试代码如下

    public class Test2 {
        public static void main(String[] args) {
        
            
        AirportDao airportDao=(AirportDao)new AirportDaoImplCglibProxy().newInstance(new AirportDaoImpl());
        
        airportDao.Buytickets();
        
        }
    
    }

    输出结果也和静态代理的结果一样

    如果目标类实现了接口 优先使用jdk动态代理生成代理类,没有实现接口在使用Cglib生成代理类

  • 相关阅读:
    第一份随笔
    慢哈希算法
    彩虹表
    基于Wireshark验证网站口令认证传输方案
    electron学习笔记2
    基于原型的软件需求获取
    《小学四则运算练习软件》结对项目报告
    201571030109 小学四则运算练习软件项目报告
    201571030109 《构建之法》速读
    个人学期总结
  • 原文地址:https://www.cnblogs.com/java888/p/10730040.html
Copyright © 2020-2023  润新知