Java代理模式学习

90 阅读4分钟

代理模式是指,为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户类和目标对象之间起到中介的作用。

换句话说,使用代理对象,是为了在不修改目标对象的基础上,增强主业务逻辑。 

客户类真正的想要访问的对象是目标对象,但客户类真正可以访问的对象是代理对象。客户类对目标对象的访问是通过访问代理对象来实现的。当然,代理类与目标类要实现同一个接口。 

例如: 有A,B,C三个类, A原来可以调用C类的方法, 现在因为某种原因C类不允许A类调用其方法,但B类可以调用C类的方法。A类通过B类调用C类的方法。这里B是C的代理。 A通过代理B访问C. 

Window系统的快捷方式也是一种代理模式。快捷方式代理的是真实的程序,双击快捷方式是启动它代表的程序。 

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

在代理模式中,我们创建具有现有对象的对象,以便向外界提供功能接口。 

介绍

意图:为其他对象提供一种代理以控制对这个对象的访问。 

主要解决:在直接访问对象时带来的问题,比如说:要访问的对象在远程的机器上。在面向对象系统中,有些对象由于某些原因(比如对象创建开销很大,或者某些操作需要安全控制,或者需要进程外的访问),直接访问会给使用者或者系统结构带来很多麻烦,我们可以在访问此对象时加上一个对此对象的访问层。 

何时使用:想在访问一个类时做一些控制。 

如何解决:增加中间层。 

关键代码:实现与被代理类组合。 

应用实例: 

⒈Windows 里面的快捷方式。 

⒉猪八戒去找高翠兰结果是孙悟空变的,可以这样理解:把高翠兰的外貌抽象出来,高翠兰本人和孙悟空都实现了这个接口,猪八戒访问高翠兰的时候看不出来这个是孙悟空,所以说孙悟空是高翠兰代理类。 

⒊买火车票不一定在火车站买,也可以去代售点。 

⒋一张支票或银行存单是账户中资金的代理。支票在市场交易中用来代替现金,并提供对签发人账号上资金的控制/

spring aop。 

优点: 

⒈清晰。 

⒉高扩展性。 

⒊智能化。 

缺点: 

⒈由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。 

⒉实现代理模式需要额外的工作,有些代理模式的实现非常复杂。 

使用场景:按职责来划分,通常有以下使用场景: 

⒈远程代理。 

⒉虚拟代理。 

⒊Copy-on-Write 代理。 

⒋保护(Protect or Access)代理。 

⒌Cache代理。 

⒍防火墙(Firewall)代理。 

⒎同步化(Synchronization)代理。 

⒏智能引用(Smart Reference)代理。 

注意事项: 

⒈和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。 

⒉和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。 

代理模式作用

A、 控制访问 

B、 增强功能 

代理模式分类

可以将代理分为两类:静态代理与动态代理 

代理的实现方式

静态代理和动态代理 

实现

我们将创建一个 Image 接口和实现了 Image 接口的实体类。ProxyImage 是一个代理类,减少 RealImage 对象加载的内存占用。 

ProxyPatternDemo,我们的演示类使用 ProxyImage 来获取要加载的 Image 对象,并按照需求进行显示。 

步骤 1 

创建一个接口。 

public interface Image { void display();} 

步骤 2 

创建实现接口的实体类。 

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

public class ProxyImage implements Image{  private RealImage realImage; private String fileName;  public ProxyImage(String fileName)this.fileName = fileName; }  @Override public void display()if(realImage == null){ realImage = new RealImage(fileName); } realImage.display(); }} 

步骤 3 

当被请求时,使用 ProxyImage 来获取 RealImage 类的对象。 

public class ProxyPatternDemo {  public static void main(String\[] args)Image image = new ProxyImage("test\_10mb.jpg");  // 图像将从磁盘加载 image.display();  System.out.println(""); // 图像不需要从磁盘加载 image.display();  }} 

步骤 4 

执行程序,输出结果: 

Loading test_10mb.jpgDisplaying test_10mb.jpg Displaying test_10mb.jpg