23种设计模式-结构型模式-代理模式

代理模式通过创建代理对象来控制对目标对象的访问,它可以扩展目标对象的功能。文章介绍了静态代理,其中代理对象与目标对象需实现相同接口,以及动态代理,包括JDK和CGLIB实现。JDK动态代理基于接口,而CGLIB通过创建目标对象的子类来实现。每种代理方式都有其特点和适用场景。
摘要由CSDN通过智能技术生成

代理模式

代理模式(Proxy Pattern)是一种结构性模式。代理模式为一个对象提供了一个替身,以控制对这个对象的访问。即通过代理对象访问目标目标对象,可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。

分类

主要分为静态代理、动态代理(JDK动态代理、CGLIB动态代理)。

博文推荐

设计模式-代理模式(静态代理、动态代理、cglib代理)

案例描述

本例以教师教学为例。教师教学或发起随堂考试。

一、静态代理

静态代理是定义父类或者接口,然后被代理对象(即目标对象)与代理对象一起实现相同的接口或者是继承相同父类。代理对象与目标对象实现相同的接口,然后通过调用相同的方法来调用目标对象的方法。

  • 特点:代理对象与目标对象(被代理对象)都需要实现接口
  • 优点:可不修改目标对象的功能,通过代理对象对目标功能扩展。
  • 缺点:因为代理对象需要与目标对象实现一样的接口,所以会有很多代理类,一旦接口增加方法,目标对象与代理对象都要维护。

本例UML类图关系

在这里插入图片描述

具体代码实现

TeacherService(教师服务)

package com.lcq.proxypattern;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: 教师服务
 */
public interface TeacherService {
    void teach();
}

TeacherServiceImpl(教师服务实现类)

package com.lcq.proxypattern;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: 教师服务实现类
 */
public class TeacherServiceImpl implements TeacherService{

    @Override
    public void teach() {
        System.out.println("教书育人");
    }
}

TeacherServiceProxy(教师服务代理)

package com.lcq.proxypattern;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: 教师服务代理类
 */
public class TeacherServiceProxy implements TeacherService{
    //目标对象(被代理对象)
    private TeacherService target = null;

    public TeacherServiceProxy(TeacherService target){
        this.target = target;
    }

    @Override
    public void teach() {
        System.out.println("静态代理开始");
        target.teach();//执行目标对象的方法
        System.out.println("静态代理结束");
    }
}

Client

package com.lcq.proxypattern;

import com.sun.javaws.Main;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: 静态代理
 */
public class Client {
    public static void main(String[] args) {
        //目标对象(被代理对象)
        TeacherService target = new TeacherServiceImpl();
        //代理对象
        TeacherService proxy = new TeacherServiceProxy(target);

        System.out.println(proxy);
        System.out.println(proxy.getClass());
        proxy.teach();
    }
}

运行结果

com.lcq.proxypattern.TeacherServiceProxy@2503dbd3 class 
com.lcq.proxypattern.TeacherServiceProxy 
静态代理开始 
教书育人 
静态代理结束

由测试可以看出通过代理类可以扩展目标对象方法,实现目标方法功能增强。

二、JDK动态代理

利用JDK的API动态的在内存中创建代理对象,主要利用反射中的import java.lang.reflect.Proxy
通过Proxy.newProxyInstance()方法

Proxy.newProxyInstance(
	ClassLoader loader,//目标对象类加载器
	Class<?>[] interfaces,//目标对象的接口类型
 	InvocationHandler h)//执行目标对象的方法回调
  • 特点:目标对象需要实现接口,而代理对象无需实现接口。当目标对象增加方法时,目标对象只需覆盖相应的方法,而动态代理无需覆盖。相比于静态代理而言,JDK动态代理更加灵活,但依旧违反了开闭原则。

本例UML类图关系

在这里插入图片描述

具体代码实现

TeacherService

package com.lcq.proxypattern.dynamic;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: TODO
 */
public interface TeacherService {
    /** 
     * 
     * @author coder
     * @date 2023/3/11 15:57
     * @description 教学
     * @param 
     * @return 
     */
    void teach();
    /**
     *
     * @author coder
     * @date 2023/3/11 14:34
     * @description 随堂考试
     * @param subject 考试科目
     * @return 返回考试科目相关信息
     */
    String test(String subject);
}

TeacherServiceImpl

package com.lcq.proxypattern.dynamic;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: 教师服务实现类
 */
public class TeacherServiceImpl implements TeacherService {

    @Override
    public void teach() {
        System.out.println("教书育人");
    }

    @Override
    public String test(String subject) {
        System.out.println(subject+"随堂考试开始");
        return "今日考试科目-"+subject;
    }
}

ProxyFactory(代理工厂)

package com.lcq.proxypattern.dynamic;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: JDK代理工厂
 */
public class ProxyFactory {
    //目标对象(被代理对象)
    private Object target;

    public ProxyFactory(){

    }

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

    public void setTarget(Object target){
        this.target = target;
    }

    public Object getProxyInstance(){
        return Proxy.newProxyInstance(
                target.getClass().getClassLoader(), //目标对象类加载器
                target.getClass().getInterfaces(), //目标对象的接口类型
                new InvocationHandler() {//执行目标对象的方法回调
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        System.out.println("jdk动态代理开始");
                        Object returnVal = method.invoke(target, args);
                        System.out.println("jdk动态代理结束");
                        return returnVal;//目标对象方法返回值
                    }
                });
    }
}

Client

package com.lcq.proxypattern.dynamic;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: JDK动态代理
 */
public class Client {
    public static void main(String[] args) {
        //目标对象(被代理对象)
        TeacherService target = new TeacherServiceImpl();
        //代理工厂
        ProxyFactory proxyFactory = new ProxyFactory();
        //设置代理对象
        proxyFactory.setTarget(target);
        //代理对象
        TeacherService proxy = (TeacherService) proxyFactory.getProxyInstance();

        System.out.println(proxy.getClass());
        System.out.println("----------------");
        proxy.teach();
        System.out.println("----------------");
        String math = proxy.test("数学");
        System.out.println("----------------");
        System.out.println("test方法返回值:"+math);
    }
}

运行结果

class com.sun.proxy.$Proxy0
----------------
jdk动态代理开始
教书育人
jdk动态代理结束
----------------
jdk动态代理开始
数学随堂考试开始
jdk动态代理结束
----------------
test方法返回值:今日考试科目-数学

三、CGLIB动态代理

Cglib代理也叫作子类代理,它使目标对象不需要实现接口,是在内存中构建一个子类对象从而实现对目标对象功能扩展,有的也将Cglib代理归属到动态代理。

  • 特点:目标对象与代理对象都无需实现接口。
  • 相关jar包
    在这里插入图片描述

特别注意:代理的类不能为final,否则报错java.lang.IllegalArgumentException ,如果目标对象的方法如果为final或static,那么就不会被拦截(即不会执行目标对象额外的业务方法)。

本例UML类图关系

在这里插入图片描述

具体代码实现如下

TeacherServiceImpl

package com.lcq.proxypattern.cglib;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: 教师服务
 */
public class TeacherServiceImpl {
    public void teach() {
        System.out.println("教书育人");
    }
    public String test(String subject){
        System.out.println(subject+"随堂考试开始");
        return "今日考试科目-"+subject;
    }
}

ProxyFactory

package com.lcq.proxypattern.cglib;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: cglib的动态代理
 */
public class ProxyFactory implements MethodInterceptor {
    //目标对象
    private Object target;

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

    //获取代理对象实例
    public Object getProxyInstance(){
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(target.getClass());//设置目标对象
        enhancer.setCallback(this);//当前对象回调
        return enhancer.create();//创建代理对象
    }

    @Override
    public Object intercept(
            Object o,//代理对象
            Method method,//执行的方法
            Object[] args,//方法参数
            MethodProxy methodProxy//代理方法
    ) throws Throwable {
        System.out.println("cglib动态代理开始");
        Object returnVal = method.invoke(target, args);
        System.out.println("cglib动态代理结束");
        return returnVal;
    }
}

Client

package com.lcq.proxypattern.cglib;

/**
 * @Author: coder
 * @CreateTime: 2023-03-11
 * @Description: cglib动态代理
 */
public class Client {
    public static void main(String[] args) {
        //目标对象
        TeacherServiceImpl target = new TeacherServiceImpl();
        //代理对象
        TeacherServiceImpl proxy = (TeacherServiceImpl) new ProxyFactory(target).getProxyInstance();
        //执行目标对象方法
        proxy.teach();
        System.out.println("---------------------");
        String subject = proxy.test("数学");

        System.out.println("test方法返回值:"+subject);
    }
}

运行结果

cglib动态代理开始
教书育人
cglib动态代理结束
---------------------
cglib动态代理开始
数学随堂考试开始
cglib动态代理结束
test方法返回值:今日考试科目-数学
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值