Java设计模式之代理模式

目录

1.概述

2. 静态代理模式

2.1基于接口的静态代理

2.2基于继承的静态代理

2.3优缺点

3.动态代理模式

3.1JDK 动态代理

3.2 CGlib 动态代理

3.3优缺点

1.概述

-    代理模式指: 为一个对象提供一个替身,以控制对这个对象的访问。既通过代理对象访问目标对象,这样做的好处是: 可以在目标对象实现的基础上,增加额外的功能操作,即扩展目标对象的功能

- 代理模式分为: 静态代理模式和动态代理模式(JDK 和CGLIB)。

2. 静态代理模式

- 概述:  静态代理由开发者对抽象主题编写相关代理类实现,编译之后生成代理类的class.

- 使用: 静态代理在使用时,需要定义接口或者父类, 目标对象与代理对象一起实现接口或者继承共同的父类

 - 实例: 以外卖骑手为例,骑手代理顾客执行购买,等待,取餐的操作       

2.1基于接口的静态代理

- Foodie 品尝接口(抽象主题)

/**
 * 美食家---> 抽象主题: 静态代理
 */
public interface Foodie {
    /**
     * 品尝美食
     */
    void eat();
}

- RealFoodie 真实品尝类(真实主题)

/**
 * 真实美食家---> 真实主题: 静态代理
 */
public class RealFoodie implements  Foodie{
    @Override
    public void eat() {
        System.out.println("开始品尝美食....");
    }
}

- ProxyFactory 代理工厂

/**
     * 重写Foodie接口的方法
     */
    @Override
    public void eat() {
        //增加扩展功能
        System.out.println("开始购买...");
        System.out.println("开始等待...");
        System.out.println("开始配送");
        //调用目标对象方法
        foodie.eat();
    }

Test 测试类

public class Test {
    public static void main(String[] args) {
       //1.静态代理---> 基于接口
        RealFoodie realFoodie=new RealFoodie();
        //填入目标对象
        Foodie foodie=new ProxyFactory(realFoodie);
        foodie.eat();
    }
}

- 输出结果

开始购买....
开始等待....
开始配送....
开始品尝....

总结 : 以上代码可以看出: ProxyFactory代理工厂替目标对象扩展了骑手配送的功能。目标对象没有作任何更改,因此目标对象和扩展功能互不影响,职责分明。

注意 : 目标对象和代理工厂都要实现抽象主题, 这是基于接口的一种方式。

2.2基于继承的静态代理

 - 使用场景: 在代理工厂不想实现接口去扩展功能时,就可以使用继承的方式(即继承和真实主题共有的父类或直接继承真实主题)。

- Foodie 抽象主题(和上面一样没做任何改动)

- RealFoodie 真实主题(和上面一样没做任何改动)

- ProxyFactory 代理工厂

/**
 * 代理工厂直接继承真实主题--->即目标对象
 */
public class ProxyFactory extends  RealFoodie{

    /**
     * 重写父类的方法
     */
    @Override
    public void eat() {
        //扩展功能
        System.out.println("开始购买....");
        System.out.println("开始等待....");
        System.out.println("开始配送....");
        //调用父类(即目标对象)的方法
        super.eat();
    }
}

2.3优缺点

优点:

-    可以在不修改目标对象的前提下,能通过代理对象对目标功能进行扩展。

-    目标对象和代理的扩展功能职责清晰不会产生耦合。

缺点:

-   因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类。

-   一旦接口增加方法,目标对象与代理对象都要维护。

3.动态代理模式

- 概述: 动态代理是在运行时动态生成的,通过反射动态生成代理类字节码

- 分类: 动态代理模式可分为JDK动态代理(基于接口),CGlib(继承方式)。

3.1JDK 动态代理

- 实现:目标对象实现抽象接口,代理方法逻辑类实现InvocationHandler调用处理器接口。

- Foodie 抽象主题 

/**
 * 美食家--->抽象主题: JDK动态代理
 */
public interface Foodie{
    void eat();
}

- RealFoodie 真实主题

/**
 * 真实主题---> JDK动态代理
 */
public class RealFoodie implements  Foodie{
    /**
     * 品尝美食
     */
    @Override
    public void eat() {
        System.out.println("开始品尝....");
    }
}

- MethodInvocationHandler 方法逻辑调用处理类

  该类用于处理代理方法逻辑及或利用反射创建代理对象:

/**
 * 实现代理方法逻辑类----> JDK 动态代理
 */
public class MethodInvocationHandler implements InvocationHandler {

    //定义未知目标对象
    private Object target;

    public MethodInvocationHandler(Object target) {
        this.target = target;
    }
    /*
    * 创建代理工厂
    **/
    public Object getInstance()
    {
        /**
         * ClassLoader loader, 目标对象的类加载器
         * Class<?>[] interfaces, 目标对象所实现的所有接口
         * InvocationHandler h  代理的方法逻辑自动调用重写的invoke
         */
          return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),new MethodInvocationHandler(target));
    }

   /*
    * 处理代理的方法逻辑
   */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        //扩展新功能
        System.out.println("开始购买...");
        System.out.println("开始等待...");
        System.out.println("开始送餐...");
        //调用目标对象的方法
        Object invoke = method.invoke(target, args);
        return invoke;
    }
}

- Test测试类

public class Test {
    public static void main(String[] args) {
        //创建真实主题
        RealFoodie realFoodie=new RealFoodie();
        //创建代理方法逻辑
        MethodInvocationHandler methodInvocationHandler=new MethodInvocationHandler(realFoodie);
        //创建代理对象--->填入目标对象
        Foodie foodie= (Foodie) new MethodInvocationHandler(realFoodie).getInstance();
        foodie.eat();
    }
}

3.2 CGlib 动态代理

- 前置操作: 引入CGlib的jar包。

- 使用场景:目标对象不想实现接口时,CGlib使用继承来实现

- 实现: 代理方法拦截类实现MethodInterceptor 即方法拦截接口。

MethodInterceptor 代理方法拦截类

  该类用于创建代理对象并处理代理方法逻辑(对目标对象方法进行拦截) :

/**
 * 代理方法拦截类---> CGlib动态代理
 */
public class MethodInterceptor implements net.sf.cglib.proxy.MethodInterceptor {
    //目标对象
    private  Object target;

    public MethodInterceptor(Object target) {
        this.target = target;
    }

    /**
     * 创建代理对象
     */
    public Object createInstance()
    {
        //1.设置工具类
        Enhancer enhancer=new Enhancer();
        //2.设置父类
        enhancer.setSuperclass(target.getClass());
        //3.设置回调函数
        enhancer.setCallback(this);
        //4.创建代理对象
        Object o = enhancer.create();
        return  o;
    }

    /**
     * 写入拦截扩展代码
     * @param o 目标对象
     * @param method 所扩展目标对象的方法
     * @param objects 方法参数
     * @param methodProxy 代理对象
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        //扩展功能
        System.out.println("开始购买...");
        System.out.println("开始等待...");
        System.out.println("开始送餐...");
        //调用父类指定方法(拦截目标对象的方法)
        Object invoke =methodProxy.invokeSuper(o,objects);
        return invoke;
    }
}

- RealFoodie 真实主题类

/**
 * 真实主题---->CGlib动态代理
 */
public class RealFoodie {
    void eat()
    {
        System.out.println("开始品尝...");
    }
}

- Test测试类

public class Test {
    public static void main(String[] args) {
        //创建真实主题
        RealFoodie realFoodie = new RealFoodie();
        //创建代理方法拦截器并创建代理对象
        RealFoodie realFoodie1 = (RealFoodie) new MethodInterceptor(realFoodie).createInstance();
        realFoodie1.eat();
    }
}

3.3优缺点

优点:

- 如扩展功能类似时,代理工厂类对象是未知的,就可以使用一个代理对象完成扩展功能,使用时指定不同目标对象即可。

- 代理工厂无需实现抽象接口的方法,因为是利用反射在运行时创建的代理对象

缺点:

- CGlib : 通过继承的方式进行代理,无法处理被final修饰类的情况。

- JDK: 只能基于接口处理

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值