Java设计模式

Java代理模式

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

  百度百科《代理模式》

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

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

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

原来的访问关系:

通过代理的访问关系:

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

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

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

介绍

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

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

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

如何解决:增加中间层。

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

应用实例:

⒈Windows 里面的快捷方式。

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

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

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

优点:

⒈清晰。

⒉高扩展性。

⒊智能化。

缺点:

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

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

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

⒈远程代理。

⒉虚拟代理。

⒊Copy-on-Write 代理。

⒋保护(Protect or Access)代理。

⒌Cache代理。

⒍防火墙(Firewall)代理。

⒎同步化(Synchronization)代理。

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

注意事项:

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

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

代理模式作用

A、 控制访问

B、 增强功能

代理模式分类

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

代理的实现方式

静态代理和动态代理

代理模式需求

需求:用户需要购买u盘, u盘厂家不单独接待零散购买,厂家规定一次最少购买1000个以上,用户可以通过淘宝的代理商,或者微商哪里进行购买。

淘宝上的商品,微商都是 u 盘工厂的代理商, 他们代理对u盘的销售业务。

用户购买-------代理商(淘宝,微商)----- u 厂家(金士顿,闪迪等不同的厂家)

设计这个业务需要的类:

1. 商家和厂家都是提供 sell 购买u盘的方法。定义购买u盘的接口 UsbSell

2. 金士顿(King)对购买1千以上的价格是 85, 3千以上是80, 5千以上是75。 单个120元。定义UsbKingFactory类,实现UsbSell

3. 闪迪(San)对购买1千以上的价格是 82, 3千以上是78, 5千以上是72。 单个120元。定义UsbSanFactory类,实现UsbSell

4. 定义淘宝的代理商 TaoBao ,实现UsbSell

5. 定义微商的代理商 WeiShang, 实现UsbSell

6. 定义测试类,测试通过淘宝, 微商购买u盘

实现

我们将创建一个 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.jpg
Displaying test_10mb.jpg

Displaying test_10mb.jpg