虚拟代理模式(Virtual Proxy)是一种节省内存的技术它建议创建那些占用大量内存或处理复杂的对象时把创建这类对象推迟到使用它的时候在特定的应用中不同部分的功能由不同的对象组成应用启动的时候不会立即使用所有的对象在这种情况下虚拟代理模式建议推迟对象的创建直到应用程序需要它为止对象被应用第一次引用时创建并且同一个实例可以被重用这种方法优缺点并存 优点 这种方法的优点是在应用程序启动时由于不需要创建和装载所有的对象因此加速了应用程序的启动 缺点: 因为不能保证特定的应用程序对象被创建在访问这个对象的任何地方都需要检测确认它不是空(null)也就是这种检测的时间消耗是最大的缺点 应用虚拟代理模式需要设计一个与真实对象具有相同接口的单独对象(指虚拟代理)不同的客户对象可以在创建和使用真实对象地方用相应的虚拟对象来代替虚拟对象把真实对象的引用作为它的实例变量维护代理对象不要自动创建真实对象当客户需要真实对象的服务时调用虚拟代理对象上的方法并且检测真实对象是否被创建 如果真实对象已经创建代理把调用转发给真实对象 如果真实对象没有被创建 )代理对象创建真实对象 )代理对象把这个对象分配给引用变量 )代理把调用转发给真实对象 按照这种安排验证对象存在和转发方法调用这些细节对于客户是不可见的客户对象就像和真实对象一样与代理对象进行交互因此客户从检测真实对象是否为null中解脱出来另外由于创建代理对象在时间和处理复杂度上要少于创建真实对象因此在应用程序启动的时候用代理对象代替真实对象初始化 例子 假设我们建立一个JAVA程序的集成开发环境(Integrated Development Environment)这个环境包括三个功能编译运行生成JavaDoc文档在新建和编辑Java程序时最为常用的是编译和运行至于生成JavaDoc文档对于每一个Java程序不是必需的因此在Java开发环境启动时不要创建和装载实现集成开发环境全部功能的所有对象仅创建那些在编辑编译运行时用到的对象保留提供生成JavaDoc文档的对象这是一个好的设计思想这种对象创建策略能够高效地利用内存空间并且加快了集成开发环境的启动速度 假设编译运行生成JavaDoc文档这些功能分别由三个工具类提供??CompilerRuntime和JavaDoc客户对象可以访问的不同IDE操作的接口以抽象类IDEOperation的形式定义 public abstract class IDEOperation { private Compiler cmp; private Runtime rtime; public void compile(String javaFile) { pile(javaFile); } public void run(String classFile) { rtimerun (classFile); } //to be delayed until needed public abstract void generateDocs(String javaFile); public IDEOperation() { cmp = new Compiler(); rtime = new Runtime(); } } 类IDEOperation提供了编译运行java程序方法的实现作为它构造函数的一部分IDEOperation创建和装载了进行编译和执行操作的Compiler和Runtime对象生成JavaDoc文档的方法generateDocs方法被设计成抽象的方法由它的子类来实现 让我们定义抽象类IDEOperation的一个具体子类RealProcessor作为RealProcessor构造函数的一部分创建JavaDoc对象来提供生成JavaDoc文档的服务通过使用JavaDoc对象功能实现generateDocs方法 public class RealProcessor extends IDEOperation { JavaDoc jdoc; public RealProcessor() { super(); jdoc = new JavaDoc(); } public void generateDocs(String javaFile) { jdocgenerateDocs(javaFile); } } 通过上面的实现RealProcessor类包含了编译运行和生成JavaDoc文档的所有功能像我们原来讨论的生成JavaDoc文档的功能不是每一个Java程序所必须的当RealProcessor实例化的时候包括负责生成JavaDoc文档的JavaDoc对象的一系列对象被创建推迟创建JavaDoc对象有以下优点 )加速了RealProcessor对象的创建时间因为它的构造函数创建的很少的对象 )高效地利用内存因为在不需要对象服务的时候不需要把对象保持在内存中 在不改变RealProcessor实现的前提下可以通过定义IDEOperation的另外一个子类ProxyProcessor来实现虚拟代理因为RealProcessor和ProxyProcessor共享相同的接口客户对象可以用ProxyProcessor代替RealProcessor图展示了类层次 Figure : IDEOperation Class Hierarchy public class ProxyProcessor extends IDEOperation { private RealProcessor realProcessor; public void generateDocs(String javaFile) { /* In order to generate javadocs the proxy loads the actual object and invokes its methods */ if (realProcessor == null) { realProcessor = new RealProcessor(); } realProcessorgenerateDocs(javaFile); } } 作为自己的实例变量ProxyProcessor维护了RealProcessor对象的一个引用作为generateDocs方法的一部分ProxyProcessor检测引用变量是否被初始化为RealProcessor对象如果没有被初始化它创建一个RealProcessor对象并把这个对象分配给它的实例变量一旦RealProcessor对象已经被创建就调用其上的generateDocs方法 实际上也就是当客户对象第一次请求产生javadoc文档时RealProcessor才被初始化装入内存中反过来直到客户需要为Java程序生成javadocs时JavaDoc对象才会被创建和装入内存中 客户对象像调用真实处理对象一样调用ProxyProcessor上的方法并不需要关心(知道)RealProcessor对象是否存在 至于验证检测和ProxyProcessor和RealProcessor之间的交互这样的细节对于客户对象是透明的 public class Client { public static void main(String[] args) { /* At this point objects required for the compile and run operations are created but not the objects that provide the generate Javadoc functionality */ IDEOperation IDE = new ProxyProcessor(); pile(testjava); IDErun(testclass); /* The Javadoc functionality is accessed For the first time and hence the Object offering the Javadoc generation Functionality is loaded at this point */ IDEgenerateDocs(testjava); } } |