容器,对象生命周期管理的基石

郑重申明:包括本文在内的很多技术文章,大多出自山外高人,而非Fans。
Fans暂时没有能力写作优秀的技术文章,Fans只是转载、浓缩、加入部分自己的代码而已。

 
           对象的生命周期管理在基于面向对象的编程语言中是一个永恒的话题。从语法上讲,面向对象的高级编程语言都是以“对象”为中心的。而对象之间的继承关系、嵌套引用关系所形成的对象树结构为我们进行对象级别的逻辑操作提供了足够的语法支持。但这样一来,对象之间所形成的复杂关系也为对象生命周期管理带来了问题:
 
         在程序的运行期,应如何创建我们所需要的对象?
       当创建一个新的对象时,如何保证与这个对象所关联的依赖关系(其依赖对象)也能够被正确地创建出来?
 
       这两大问题不仅是面向对象的编程语言中的核心问题,也是每个框架在进行设计时必须越过的坎。业界对于这样的问题也早有公论:
       结论 为了更好地管理对象的生命周期,我们有必要在程序逻辑中引入一个额外的编程元素,这个元素就是容器(Container)。
 

  1.对象的生命周期管理

   两大问题实际上涵盖了对象生命周期管理的两个方面:
  在程序的运行期,对象实例的创建和引用机制。
  对象与其关联对象的依赖关系的处理机制。
 
  为了帮助大家更好地对这两大方面进行解读,我们在这里引入一个非常重要的概念:控制反转(Inversion of Control)。
 
     控制反转是对象生命周期管理中的一个核心概念,由软件大师××提出,并以此为基础创造了一个大家更为熟悉和理解的概念:依赖注入。
 
     那么什么是控制反转呢?在使用基于面向对象的编程语言进行开发时,对象的概念是实现业务逻辑的基础核心。而要真正实现一个复杂的业务需求,则离不开多个对象彼此之间的通力协作来共同完成。对象关系模型中写作的真正含义,正是对象通过其依赖对象的帮助,完成其业务逻辑的过程。而动作特性的对象的嵌套引用,是对象之间精诚合作、协作完成业务逻辑的基本途径,也是对象之间形成依赖关系的
根本原因。在这种情况下,每个对象不得不依赖于与其写作的对象(也就是它所依赖的对象)的引用和构建。更加通俗地说:
 
  结论 每个对象自身对于逻辑的执行能力,被其所依赖的对象反向控制了,这也是控制反转的本质含义。
 
      当对象之间的这种依赖关系与运行期对象的构建机制相结合时,情况就会变得更加复杂。因为在对象创建的时候,除了需要考虑这个对象本身作为一个实例的创建过程,还需要考虑与这个对象形成依赖关系的关联对象的实例化过程。前一个过程能够使对象自身的生命周期得到控制和管理;而后一个过程,则保证了程序在运行期的使用不会受到其所依赖的对象的生命周期的限制。

      因此,我们可以看出对象的生命周期管理的两个不同方面的内容是密不可分的。对象的创建是对象依赖关系管理的基础,没有对象的创建过程,其所关联的对象的生命周期也就无从谈起;另外一个方面,如果对象的依赖关系无法被正确处理,那么我们创建出来的依赖对象也就失去了活力,因为它失去了一个对象最为基本的与其它对象协作的能力。
 
2.容器(Container)的引入
     控制反转概念的提出对我们编写程序提出了额外的要求,因为我们不得不去实现“获取依赖对象”这一基本的逻辑功能,从而使得对象与对象之间的协作和沟通变得更为畅通。既然如此,那么如何实现这个获取依赖对象的过程就值得我们仔细掂量。如果这个过程靠程序逻辑自身来实现(也就是说在程序的运行过程中自行管理),那么我们至少可以预见到这种编程模式存在着三大弊端:
 
  对象将频繁创建,效率大大降低(尽管在大多数情况下,这些对象都是无状态的单例对象);
  对象的创建逻辑与业务逻辑代码高度耦合,使得一个对象的逻辑关注度大大分散;
  程序的执行效率大大降低,由于无法区分明确的职责,很难针对对象实现的业务逻辑进行单元测试。
 
  正是看到了这些弊端,业界的软件大师就提出一条“获取依赖对象的过程”的最佳实践:
应该引入一个与具体的业务逻辑完全无关的额外的编程元素容器来帮助进行对象的生命周期管理。
 
  引入容器是以Java为代表的面向对象的编程语言发展过程中的一个重要里程碑。因而,几乎所有的开源框架都有自己的容器实现。甚至有些框架(诸如Spring),更是以容器作为其最核心的基础构建。既然引入容器的目的是为了解决对象生命周期管理中所遇到的问题,那么这一额外的编程元素自身的设计也必须遵循一定的原则:

  容器应该被设计成一个全局的、统一的编程元素。
  这一点几乎无须多做解释。在运行期获取对象实例可能发生在程序的任何一个角落,因此容器作为一个
辅助元素也可能随时在任何地方被调用。这就不得不要求容器对象是一个全局对象。
 
  在最大程度上降低容器对业务逻辑的入侵。
  这是进行容器设计时需要考虑的一个最重要的问题。因为我们引入容器这个额外元素来帮助管理对象生命周期的初衷之一,就是我们希望能够把对象生命周期管理的部分从具体的业务逻辑中提取出来,使得业务逻辑本身能够方便地进行单元测试。
 
  容器应该能够提供简单而全面的对象操作接口。
 引入容器的目的就是为了进行对象操作。因而,简单而全面在这里所表达的意思,一方面是说针对对象的操作接口应该一目了然;另外一个方面,针对对象的操作接口应该涵盖对象生命周期管理的所有内容。

3.容器(Container),不是容器(Collection)

  在Java世界中有一个被称之为Collection的接口,用于表达一组对象的集合。由Collection引申开来的数据结构很多,比如List、Set等。这些接口都是继承自Collection接口,各自表示不同特性的数据结构。从中文翻译的角度,我们习惯把Collection翻译为“容器”,而所有相关的接口及其实现类都被成为“容器结构”。
 
我们在这里引入的容器(Container)的概念与Collection接口所表述的容器概念完全不同。容器(Collection)是一个具体的数据结构类。在容器(Collection)中存储的内容是对象。而容器(Container),却不是一个具体的数据结构类,它用于管理对象的生命周期,我们可以把它看作是一个全局的编程元素。因此,在容器(Container)中,我们将看不到具体的对象存储。整个容器(Container)
从外部看来,就如同是一个可以进行对象操作的工具类。

结论 容器(Container)由一系列对象的操作接口构成,其中应该至少包含获取对象实例以及管理对象之间的依赖关系这两类操作方法。

明确了这一条结论,能够帮助我们对容器(Container)的表现形式有更加深刻的认识,并从中体会到:
          容器的设计原则与引入容器的初衷也是一致的。

 具体的容器(Container)实现,可以参考 Spring框架或者Struts2中容器实现。(*^__^*) 

你可能感兴趣的:(spring,数据结构,编程,框架,单元测试,语言)