我们先来分析代理这个词。
一、代理
代理是英文 Proxy 翻译过来的。我们在生活中见到过的代理,大概最常见的就是朋友圈中卖面膜的同学了。
她们从厂家拿货,然后在朋友圈中宣传,然后卖给熟人。
按理说,顾客可以直接从厂家购买产品,但是现实生活中,很少有这样的销售模式。一般都是厂家委托给代理商进行销售,顾客跟代理商打交道,而不直接与产品实际生产者进行关联。
所以,代理就有一种中间人的味道。
接下来,我们说说软件中的代理模式。
二、代理模式
代理模式是面向对象编程中比较常见的设计模式。
这是常见代理模式常见的 UML 示意图。
需要注意的有下面几点:
- 用户只关心接口功能,而不在乎谁提供了功能。上图中接口是 Subject。
- 接口真正实现者是上图的 RealSubject,但是它不与用户直接接触,而是通过代理。
- 代理就是上图中的 Proxy,由于它实现了 Subject 接口,所以它能够直接与用户接触。
- 用户调用 Proxy 的时候,Proxy 内部调用了 RealSubje
三、代理模式的实例程序
我们将创建一个 Image 接口和实现了 Image 接口的实体类。ProxyImage 是一个代理类,减少 RealImage 对象加载的内存占用。
ProxyPatternDemo,我们的演示类使用 ProxyImage 来获取要加载的 Image 对象,并按照需求进行显示。
步骤 1
创建一个接口。
Image.java
public interface Image { void display(); }
步骤 2
创建实现接口的实体类。
RealImage.java
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); } }
ProxyImage.java
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 类的对象。
ProxyPatternDemo.java
public class ProxyPatternDemo { public static void main(String[] args) { Image proxyImage = new ProxyImage("test_10mb.jpg"); // 图像将从磁盘加载 proxyImage.display(); System.out.println(""); // 图像不需要从磁盘加载 proxyImage.display(); } }
步骤 4
执行程序,输出结果:
Loading test_10mb.jpg Displaying test_10mb.jpg Displaying test_10mb.jpg
四、代理模式分析
代理模式中的角色:
-
Subject(主体)
Subject角色定义了使proxy和realsubject角色之间具有一致性的接口。这个接口提供了一个使用的好处,就是client不必却分它使用的是代理对象还是真实对象。
对应实例中Printable角色 -
Proxy(代理人)
Proxy角色会尽量处理来自Client角色的请求。只有当自己不能处理的时候,就交给工作交给真实对象。代理对象只有在有必要时才会生成真实的对象。
实例中对应的是PrinterProxy对象。 -
RealSubject(真实对象)
就是实际完成工作的对象,对应实例中的Printer对象。
代理模式的类图:
- 用代理人来提升速度
关键就在于延迟初始化。
我们可以等到需要使用到真实对象的功能才初始化。这样的好处就是可以提升性能。从我们的实例中可能看不出这个优势,假设我们有一个大型系统,如果我们都在系统启动的时候,把所有功能初始化,所有实例初始化,那么显然系统的启动将会变得很慢。但如果我们采用代理模式,那么就会在必须的时候,在初始化对象。这样就加快了系统的启动速度。 - 代理和委托
其实我们学习了那么多设计模式,是不是感觉委托简直无处不在。几乎每个设计模式都会用到委托,代理模式也不意外,就是代理了对象委托了真实对象。
因为委托可以是对象之间发生联系,互相调用。所以委托在很多设计模式中都存在。
参考文章 :
- https://www.jianshu.com/p/5ab7672b935f
- https://blog.csdn.net/briblue/article/details/73928350
- https://www.runoob.com/design-pattern/proxy-pattern.html