代理模式

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

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

概念:

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

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

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

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

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

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

动态代理:在程序运行前事先并不知道真实的角色。
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生成代理类

原文地址:https://www.cnblogs.com/java888/p/10730040.html