设计模式基础篇-08-代理模式

1. 简介

代理模式就是为其他对象提供一种代理以控制对被代理对象的访问,也就是我们常说的中介;指客户端并不直接调用实际的对象,而是通过调用代理,来间接的调用实际的对象。
在现实生活中,这种情形非常的常见,比如请一个律师代理来打官司。

2. 静态代理

2.1 创建boss接口
package aaa;

public interface Boss {
    void visit();
}
2.2 创建boss接口实现类真实类
package aaa;

public class RealBoss implements Boss {

    private String name = "hello,boss";
    @Override
    public void visit() {
        System.out.println(name);
    }
}
2.3 创建Boss接口实现类秘书类
package aaa;

public class MiShu implements Boss {

    private Boss subject;

    public MiShu(Boss subject) {
        this.subject = subject;
    }

    @Override
    public void visit() {
        subject.visit();
    }
}
2.4 测试
package aaa;

public class Test01 {

    public static void main(String[] args) {
        MiShu subject = new MiShu(new RealBoss());
        subject.visit();
    }
}

在这里插入图片描述

2.5 小结

通过上面的代理代码,我们可以看出代理模式的特点,代理类接受一个Subject接口的对象,任何实现该接口的对象,都可以通过代理类进行代理,增加了通用性。

缺点:

但是也有缺点,每一个代理类都必须实现一遍委托类(比如Boss)的接口,如果接口增加方法,则代理类也必须跟着修改。其次,代理类每一个接口对象对应一个委托对象,如果委托对象非常多,则静态代理类就非常臃肿,难以胜任。

3. 动态代理

动态代理有别于静态代理,是根据代理的对象,动态创建代理类。这样,就可以避免静态代理中代理类接口过多的问题。动态代理是实现方式,是通过反射来实现的,借助Java自带的java.lang.reflect.Proxy,通过固定的规则生成。

3.1 创建boss接口
package aaa;

public interface Boss {
    void visit();
}
3.2 创建boss接口实现类真实类
package aaa;

public class RealBoss implements Boss {

    private String name = "hello,boss";
    @Override
    public void visit() {
        System.out.println(name);
    }
}

这两步和前面静态代理差不多

3.3 创建boss代理类
package aaa;

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

public class BossProxy implements InvocationHandler {
    private Object object;
    
    public BossProxy(Object object) {
        this.object = object;
    }
    
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Object result = method.invoke(object, args);
        return result;
    }
}
3.4 测试
package aaa;

import java.lang.reflect.Proxy;

/**
 * @version V1.0.0
 * @author: WangQingLong
 * @date: 2021/4/27 20:56
 * @description:
 */
public class Test01 {
    public static void main(String[] args) {
        Boss realBoss = new RealBoss();
        BossProxy proxy = new BossProxy(realBoss);

        ClassLoader classLoader = realBoss.getClass().getClassLoader();
        Boss boss = (Boss) Proxy.newProxyInstance(classLoader, new  Class[]{Boss.class}, proxy);
        boss.visit();
    }
}

创建动态代理的对象,需要借助Proxy.newProxyInstance。该方法的三个参数分别是:

  1. ClassLoader loader表示当前使用到的appClassloader。
  2. Class<?>[] interfaces表示目标对象实现的一组接口。
  3. InvocationHandler h表示当前的InvocationHandler实现实例对象。
3.5 小结

用了动态代理我们把所有代理需要实现的行为集中到了invoke这一个方法去执行,不要再写大量模板代码了,并且我们实际上可以在一个InvocationHandler代理多个接口

缺点:
如果InvocationHandler中代理了两个接口,两个接口中有完全一模一样的两个方法,就没法去区分了
代理必须基于接口,没有实现接口的类没法被代理

4. Cglib

Cglib 基于 ASM 框架操作字节码帮我们生成需要的代理对象,并且不要求实现接口,但是需要添加依赖
比静态代理和动态代理,Cglib代理可谓是备受推崇,首先它不用向静态代理和动态代理那样实现接口,其次它更方便了为我们提供了拦截器的一些接口,是我们能够更好的对一些方法的控制。

<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>
public  class UserDao {
     public void doField(){
         System.out.println("开始学习Cglib代理------------------------");
     }
     public void eat(){
         System.out.println("吃吃吃吃吃-------------------");
     }
     public void pay(){
         System.out.println("买买买买买-------------------");
     }
}

代理的类,需要继承MethodIntercepeor,然后实现接口里为我们提供的唯一的一个方法intercept在这里我们可以通过Method.invoke()方法达到调用目标类,这里不用像jdk动态代理那样需要绑定接口

public  class ProxyFactory implements MethodInterceptor {

  private Object object;

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

    public Object getProxyInstance() {
        Enhancer en = new Enhancer();
        en.setSuperclass(object.getClass());
        en.setCallback(this);
        return en.create();
    }

    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("我开始工作了");
        Object returnValue = method.invoke(object, objects);
        System.out.println("我结束工作了");
        return returnValue;
    }
}

测试:

public class Client {
    public static  void main(String args[]){
        UserDao proxy = (UserDao) new ProxyFactory(new UserDao()).getProxyInstance();
        proxy.doField();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Alan0517

感谢您的鼓励与支持!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值