【一天一个设计模式】—— 代理模式 (Proxy Pattern)

定义:

Provide a surrogate or placeholder for another object to control access to it.
为其他对象提供一种代理以控制对这个对象的访问。

定义说的简明扼要,代理模式就是提供了另一种访问对象的方式。


代理有四大类:

1.远程代理(Remote Proxy): 控制对远程对象(不同地址空间)的访问,它负责将请求及其参数进行编码,并向不同地址空间中的对象发送已经编码的请求。
2.虚拟代理(Virtual Proxy): 根据需要创建开销很大的对象,它可以缓存实体的附加信息,以便延迟对它的访问,例如在网站加载一个很大图片时,不能马上完成,可以用虚拟代理缓存图片的大小信息,然后生成一张临时图片代替原始图片。
3.保护代理(Protection Proxy): 按权限控制对象的访问,它负责检查调用者是否具有实现一个请求所必须的访问权限。
4.智能代理(Smart Reference): 取代了简单的指针,它在访问对象时执行一些附加操作: 记录对象的引用次数;当第一次引用一个持久化对象时,将它装入内存;在访问一个实际对象前,检查是否已经锁定了它,以确保其它对象不能改变它。


代理模式有两种:

1.静态代理: 在编译时就已经实现,编译完成后代理类是一个实际的class文件。

2.动态代理: 在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中。

UML图
在这里插入图片描述
下面我们通过代码【RUNOOB的例子】来看一下静态代理

1.创建接口

public interface Image {
   void display();
}

2.创建实现类,即被代理的对象

public class RealImage implements Image {
 
   private String fileName;
 
   public RealImage(String fileName){
      this.fileName = fileName;
   }
 
   @Override
   public void display() {
      System.out.println("This is" + fileName);
   }
}

3.创建代理类

public class ProxyImage implements Image{
 
   private RealImage realImage;
   private String fileName;
   //构造代理对象时传入目标对象
   public ProxyImage(String fileName,RealImage realImage){
      this.fileName = fileName;
      this.realImage = realImage;
   }
 
   @Override
   public void display() {
      realImage.display();
   }
}

4.测试,使用代理获取对象

public class ProxyPatternDemo {
   
   public static void main(String[] args) {
   	  RealImage realImage = new RealImage();
   	  //创建代理对象
      Image image = new ProxyImage("01.jpg",realImage);
      image.display(); 
   }
}

通过代码可以看出,静态代理的缺点暴露了出来:由于代理只能为一个类服务,如果需要代理的类很多,那么就需要编写大量的代理类,比较繁琐。


动态代理

使用JDK动态代理的三大步骤:

  1. 通过实现InvocationHandler接口来自定义自己的InvocationHandler
  2. 通过Proxy.newProxyInstance( )方法创建动态代理对象
  3. 通过代理对象调用目标方法
public interface IHello {
    void sayHello();
}
public class HelloImpl implements IHello {
    @Override
    public void sayHello() {
        System.out.println("Hello world!");
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
 
public class MyInvocationHandler implements InvocationHandler {
 
    /** 目标对象(被代理对象) */
    private IHello target;
 
    public MyInvocationHandler(IHello target){
        this.target = target;
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("------插入前置通知代码-------------");
        // 执行相应的目标方法
        Object rs = method.invoke(target,args);
        System.out.println("------插入后置处理代码-------------");
        return rs;
    }
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

public class MyProxyTest {
    public static void main(String[] args) throws Exception {

        IHello  iHello = (IHello) Proxy.newProxyInstance(IHello.class.getClassLoader(), // 加载接口的类加载器
                new Class[]{IHello.class}, // 一组接口
                new MyInvocationHandler(new HelloImpl())); // 自定义的InvocationHandler
        
        iHello.sayHello();
    }
}

动态代理深入:

TODO 待补充… …

静态代理和动态代理的区别:

JDK静态代理是通过直接编码创建的,而JDK动态代理是利用反射机制在运行时创建代理类的。


总结

1.优点:

1、职责清晰。 2、高扩展性。 3、智能化。

2.缺点:

1、由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。
2、实现代理模式需要额外的工作,有些代理模式的实现非常复杂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

Uranus^

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值