设计模式之代理模式

在代理模式(Proxy Pattern)中,一个类代表另一个类的功能。这种类型的设计模式属于结构型模式。

代理模式分为静态代理和动态代理

1. 静态代理模式

在静态代理中,我们需要一个依赖现有对象的代理对象来执行现有对象的方法,代理对象和现有对象都要实现同一个接口,就好像我们租房子一样,我们可能直接找到房东,也可能通过中介租房,那么通过中介就是一种代理,他们之间的关系如下图
在这里插入图片描述

public interface Rent {
    public void rent();
}

// 房东
public class Landlord implements Rent {
    @Override
    public void rent() {
        System.out.println("房东出租房子");
    }
}

// 中介
public class LandlordProxy implements Rent {
    private Rent landlord;
    @Override
    public void rent() {
        System.out.println("中介帮房东出租房子");
        if (landlord == null) {
            landlord = new Landlord();
        }
        landlord.rent();
        // 可以对方法进行增强等
        System.out.println("中介收取手续费");
    }
}

// 租客
public class Tenant {
    public static void main(String[] args) {
        new Tenant().rentHouse();
    }
    public void rentHouse() {
        Rent proxy = new LandlordProxy();
        proxy.rent();
    }
}

运行效果如下
在这里插入图片描述

2. 动态代理

动态代理与静态代理最重要的区别便是代理对象的生成方式,静态代理中每一个代理类只为一个类服务,但是如果类比较多的时候,便要编写大量的代理类,而动态代理则很好的解决了这一个问题,动态代理是利用反射机制在程序运行时动态生成对象,在jdk动态代理中主要使用的是Proxy类InvocationHandle接口
Rent接口和Landlord类不变,创建一个RentHandle实现InvocationHandle接口

public class RentHandle implements InvocationHandler {
    // 被代理对象
    private Object target;
    public RentHandle(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    	// 可以对方法进行前置和后置增强,相当于Spring中的环绕通知
    	// 比如给某个方法增加日志等
		System.out.println(method.getName() + "方法执行时间" + new SimpleDateFormat("yyyy-MM-dd hh:mm").format(new Date()));
        // 实际调用Landlord的rent方法
        method.invoke(target, args);
        System.out.println(method.getName() + "方法执行后");
        return null;
    }
}

// 租客
public class Tenant {
    public static void main(String[] args) {
        new Tenant().rentHouse();
    }
    public void rentHouse() {
        Rent landlord = new Landlord();
        InvocationHandler handler = new RentHandle(landlord);
        Rent rentProxy = (Rent) Proxy.newProxyInstance(landlord.getClass().getClassLoader(), landlord.getClass().getInterfaces(), handler);
        System.out.println("代理对象->" + rentProxy.getClass().getName());
        rentProxy.rent();
    }
}

运行效果如下
在这里插入图片描述
实现动态代理的步骤

  1. 首先需要一个实现了接口的被代理类
  2. 创建一个Handle类实现InvocationHandle接口
  3. 在Handle的invoke方法中编写相应代码,如增加日志等
  4. 获取代理对象,通过Proxy类的newProxyInstance方法获取代理对象,然后转化为相应类型
  5. 使用代理对象,调用相关方法即可得到一个增强后的方法

3. 静态代理和动态代理的区别和联系

  1. 静态代理代理类需要对被代理类的每个方法都编写相应的代码,而动态代理只需在invoke方法中编写一次
  2. 静态代理中一个代理类只为一个类服务,而动态代理可以根据传入的目标类对象和接口为多个类服务,实现了代码的复用
  3. 静态代理针对性较强,可以针对被代理类的某个方法进行特殊处理,而动态代理一般只能做一些通用的的处理,如打印日志
  4. 静态代理和动态代理都需要被代理类实现某个接口

4. JDK动态代理和CGLIB动态代理

  1. JDK动态代理:使用JDK的Proxy代理类,JDK的动态代理要求目标对象必须实现接口,这是Java设计上的要求
  2. CGLIB动态代理:CGLIB动态代理的生成原理是生成目标类的子类,而子类是增强过的,这个子类对象就是代理对象。所以使用CGLIB生成动态代理,要求目标类必须能够被继承,即不能是final修饰的类,方法也不能是final的
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值