Java代理模式

首先举一个实例 

消费者(客户端)--->商店(代理类)--->工厂(目标类)

当一个消费者想要购买可乐,中间的关系为,

客户端:消费者

代理类:负责进货并出售可乐的商店

目标类:生产可乐并出售的工厂

其中,代理类和目标类的功能一致,都是销售可乐。

 

代理模式的作用

1. 功能增强:在原有的功能上增加了新的功能

2. 访问限制:代理类不让你访问目标类

 

实现代理的方式

1. 静态代理

(1)代理类自己手动实现 ,自己创建Java类表示代理类

(2)每个代理类需要代理的目标类是确定的

  静态代理实现简单容易理解,但也有局限性,当目标类的代理类数量很多时,如果目标类数量增加,代理类也需要成倍的增加(天猫可乐代理和京东可乐代理变成了天猫可口可乐代理、天猫百事可乐代理和京东可口可乐代理和京东百事可乐代理)。其次,如果之后在接口中增加一个方法,此时程序会出错,因为继承该接口的目标类和代理类中有未实现的方法,当类的数量越多,修改代码的工作量越大,出错的概率越高。

实现步骤:

(1)创建一个接口,定义卖可乐的方法

public interface ColaSell {
    float sell(int amount);
}

(2)创建目标类(即工厂),实现(1)中的接口

// 目标类可口可乐,不接受消费者的单独购买
public class Coca implements ColaSell {
    @Override
    public float sell(int amount){
        return amount * 2.5f;
    }
}

(3)创建代理类(即商店),实现(1)中的接口

public class JingDong implements ColaSell {
    // 声明代理的厂家具体为可口可乐
    private final Coca factory = new Coca();

    // 实现可乐销售功能
    @Override
    public float sell(int amount){
        // 运费
        float freight = 10;
        // 代理向厂家发送订单,返回订单价格
        float price = factory.sell(amount);
        // 代理将可乐出售给消费者,消费者需要额外支付代理索要的利润
        price += 0.5 * amount;
        // 消费满59包邮
        if (price >= 59) return price;
        else return (price + freight);
    }
}

(4)创建客户端类(即消费者),调用代理类的方法买可乐

public class Customer {
    public static void main(String[] args) {
        JingDong cola_JingDong = new JingDong();
        float price_JingDong = cola_JingDong.sell(2);
        System.out.println("消费者从京东购买两瓶可乐共花费:" + price_JingDong + "元");
    }
}

 

2. 动态代理

当目标类数量很多时,可以使用动态代理,避免静态代理的缺点。

在动态代理中,即使目标类的数量很多,代理类的数量也可以很少,同时,当修改接口中的方法时,不会影响代理类。

动态代理的原理:在程序的执行过程中,利用JDK的反射机制,创建代理类对象,并动态地指定要代理的目标类。

动态:在程序的执行过程中,调用JDK提供的方法,创建代理类对象。

换句话说:动态代理就是一种创建Java对象的能力,让你不用创建JingDong类,就可以创建代理类对象。

动态代理常用的实现方式有两种:

(1)使用JDK动态代理:使用Java反射包(java.lang.reflect)中的类(InvocationHandler、Method、Proxy)和接口实现动态代理功能。

(2)通过CGLB动态代理:CGLB是一个第三方工具库,能创建代理对象,在很多框架(如Mybatis、Spring)中都可以使用。CGLB通过继承目标类,创建它的子类,重写子类中的同名方法,实现功能修改。CGLB对目标类的要求比较宽松,只要能继承就可以,因此目标类和其中的方法不能是final。

使用JDK的Proxy实现代理,要求目标类和代理类必须实现相同的接口,如果目标类没有接口就不能用该方法实现。对于无接口的类,想要实现动态代理就要使用CGLB来实现。

JDK动态代理的实现:

反射包java.lang.reflect中的3个类InvocationHandler、Method、Proxy

(1)InvocationHandler接口(调用处理器)中只有一个方法invoke(),代理类对象要实现的功能代码( 1.调用目标类方法  2.功能增强 )写在invoke()中

/*
invoke方法原型
Object proxy:JDK创建的代理类对象,不需要赋值
Method method:目标类方法,JDK提供Method对象
Object[] args:目标类方法参数,JDK提供
*/
public
Object invoke(Object proxy, Method method, Object[] args)

用法:

1.创建类实现InvocationHandler接口

2.重写invoke()方法,把原来静态代理中代理类要实现的方法写在里面

(2)Method类可以通过method.invoke()执行某个目标类中的方法

method.invoke(目标类对象, 方法的参数)

(3)Proxy类中的静态方法newProxyInstance()代替new创建代理对象

/*
ClassLoader loader:类加载器,负责向内存中加载对象
Class<?>[] interfaces:目标对象实现的接口
InvocationHandler h:我们自己写的代理类对象要完成的功能
newProxyInstance返回值就是目标类对象的代理对象
*/
public
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)

 

posted @ 2022-10-06 12:00  角落蘑菇  阅读(65)  评论(0)    收藏  举报