Pennant的日常
分享工作上的点点滴滴

2.4扩展接口(Extension Interface)

1.问题

      适应应用程序需求的改变常常需要对组件功能的修改和扩展。有时可以在发布组件给应用程序开发人员之前预计到所有的接口的改变。如果不能仔细处理这些改变的话,它们就会破坏现有的使用组件的代码。为了避免这些问题,把组件设计为支持预料到与预料不到的改进也许是必需的。这要求解决以下4种强制条件:

      1)当组件接口没有改变时,对组件实现的修改应不破坏现有的客户机代码。

      2)当开发人员用外部可见的新服务扩展组件时,不应破坏现有的客户机代码。理想情况下,应该没有必要重新编译客户机代码。

      3)组件功能的改变或者扩展应该是相对直接的,既不膨胀现有的组件接口,又不动摇现有组件的内部体系结构。

      4)应该可以使用同一接口远程地或者局部地访问组件。如果组件和它们的客户机跨越网络节点,那么应能分离组件的接口和实现。

 

2.解决方案

      通过扩展接口导出组件功能,每个语义相关的操作集对应于一个接口。组件必须至少实现一个扩展接口。为了给组件增加新的功能,或者修改现有的组件功能,导出新的扩展接口而不是修改现有的接口,而且,编程使客户机通过它的扩展接口而不是它的实现来访问组件。因此,客户机仅依赖于对组件的不同角色,组件中的每个角色由一个独立的扩展接口来表示。

      为使客户机能创建组件实例并且获取组件扩展接口,我们引入额外的间接方法。例如,为创建组件实例的每个组件类型引入一个相关联的组件工厂。确保它返回一个最初的接口引用,客户机能使用它来获取其他组件的扩展接口。类似地,确保每个接口从定义所有组件公共功能特性的根接口(root interface)继承。所有其他的扩展接口从根接口派生,这确保它们最少提供根接口所导出的功能。

 

3.结构

      组件(Component)聚合和实现多种类型的与服务相关的功能。常常把这个功能划分为几个独立的角色,每个角色定义一个语义相关的操作集。

      扩展接口(Extension interface)导出经过选择的组件实现的功能。对应于组件所实现的每个角色都有一个扩展接口存在。另外,扩展接口隐式地指定描述客户机应如何使用组件功能的协定。这个协定定义了调用扩展接口方法的协议,例如可接受的参数类型和调用方法的次序。

     

 

      根接口(root interface)是一个特殊的扩展接口,它提供3种类型的功能特性:

      1)核心功能特性(Core functionality)。所有扩展接口都必须支持它们(如允许客户机获取它们请求的接口的功能特性)。这个功能特性定义组件必须实现的允许客户机获取接口和在接口之间导航的基本机制。

      2)领域无关功能(Domain-independent functionality)。例如管理组件生存期的方法。

      3)与领域有关的功能特性(Domain-specific functionality)。所有组件在一个特殊领域范围内应该提供的功能。

      尽管根接口必须实现核心功能特性,但它不必支持领域无关或者领域有关的功能特性。然而,所有扩展接口必须支持根接口定义的功能。因为每个扩展接口可以扮演根接口的角色,它保证每个扩展接口能代表客户机请求返回任何其他的扩展接口。

     

 

      客户机只能通过扩展接口访问组件提供的功能。客户机获取一个初始扩展接口的引用之后,它能够使用这个引用来获取组件支持的任何其他扩展接口。

      为获取初始引用,客户机同与特定组件类型相关联的组件工厂交互。这个组件工厂将它的处理特性与组件的创建和初始化特性分离出来。当客户机创建一个新的组件实例时,它把这项任务委托给合适的组件工厂。

      当成功地创建组件之后,组件工厂将对扩展接口的引用返回给客户。组件工厂也许允许客户机请求特定类型的初始扩展接口。工厂也可以提供一些功能定位和返回现有组件实例的引用。

     

 

4.实现

      1)确定设计和长期应用需求的平稳性。在运用扩展接口模式之前,有必要确定它是否真正需要。尽管这种模式对某些强制条件而言是强有力的解决方法,但实现并不容易,如果随意应用,就会使软件设计极端复杂化。

      2)分析领域并指定与领域有关的组件模型。标识要实现哪个组件,也标识组件必须提供的功能的领域模型。需要指定组件模型以实现被标识的组件:

        ·如果组件限制在单一应用领域或者相关领域的较小集合,那么考虑定义一个与领域有关的组件模型,此组件模型是为正被开发的应用程序或者应用程序族定制的。

        ·相反,如果组件必须运用于宽范围的应用程序,或者甚至跨越多个领域,那么考虑使用现有的组件技术,例如微软COM,Enterprise JavaBeans或者CORBA组件模型。

        在后一种情况,可以跳过下一个实现活动,因为这些组件模型定义了指定的基础设施。

      3)指定根接口。确定实现活动中所标识的每种类型的功能特性是否应该是根接口的一部分,或者被分离到扩展接口。按照这个标准迭代进行3个子活动:

        3.1)指定核心功能特性

        ·扩展接口获取。根接口最少必须包含向客户机返回扩展接口引用的方法。这个方法返回的信息类型很大程度上依赖于编程语言。

        ·唯一的命名。必须使用整数或者字符串命名扩展接口。编程人员和简单的管理工具更容易读取字符串,但整数值所占空间更小,能更有效地处理。

        ·错误处理。组件开发人员必须确定当客户机请求一个并不支持的扩展接口时,组件应该做什么。例如,组件可以返回一个错误值,或者引发一个异常。

        3.2)指定与领域无关的服务。除定义获取扩展接口的方法之外,根接口也能为各种领域无关的服务提供方法。

        ·引用计数(Reference counting)。

        ·运行时映像(Run-time reflection)。这种机制允许组件发布有关它们支持的指定角色,扩展接口和方法的信息。使用这一知识,客户机能动态地构造和发送方法调用。

        3.3)指定与领域相关的功能特性。如果所有实现根接口的组件提供这个功能的话,那么根接口也能导出领域相关的功能。

      4)引入通用扩展接口。通用扩展接口包含功能角色,此角色必须由多个组件提供,并且不包含在根接口中。应该为每个角色定义一个独立的扩展接口。

      5)定义与组件有关的扩展接口。在实现活动3)和4)中指定需要导出一般组件功能的扩展接口。这个实现活动定义附加的接口,此接口是与某一组件有关的,或者只可用于受限范围的组件。

      6)实现组件。

        6.1)指定组件实现策略。这个活动确定依据下列3个策略应该如何链接扩展接口实现:

        ·多重继承(Multiple inheritance)。在这个策略中,组件类继承它的所有扩展接口。

        ·嵌套类(Nested classes)。在这个策略中,扩展接口可以实现为组件类内的嵌套类。组件类实例化每个嵌套类的单件实例。一旦客户机查询一个特定的扩展接口时,getExtension()方法实现返回合适的嵌套类对象。

        ·独立接口类(Separate interface classes)。扩展接口可以使用桥或者适配器模式实现独立于组件自身的独立类。当应该扩展接口模式重新分解并没有实现模式的一个现有组件时,这个策略特别有用。

        6.2)实现获取扩展接口的机制。当代表客户机实现获取扩展接口的一般方法时,应该确保方法实现符合三个约定:

        ·自反性(Reflexivity)。当客户机向扩展接口A查询同一扩展接口A时,客户机必须总能接收到同一个引用A。

        ·对称性(Symmetry)。如果客户机能从扩展接口A获取扩展接口B,那么它也必须能从扩展接口B获取扩展接口A。

        ·传递性(Transitivity)。如果客户机能从扩展接口A获取扩展接口B,从扩展接口B获取扩展接口C,那么它必须可以从扩展接口A直接获取扩展接口C。

        6.3)实现引用计数机制(可选的)。

        6.4)选择并发策略。在并发或者网络化系统中,多个客户机能同时访问一个特殊的扩展接口。不同的扩展接口实现也许在组件实现范围内共享状态和资源。因此,组件实现范围内的临界区分和状态必须被串行化以防止客户机的并发访问造成破坏。

        6.5)使用所选择的组件实现策略实现扩展接口功能。这种实现活动大部分是与领域有关的或者与应用有关的,因此没有需要处理的通用问题。

      7)实现组件工厂。每个组件类型必须实现一个工厂,客户机要使用这个工厂来获得组件类的实例。这包括3个子活动:

        7.1)定义组件工厂和组件之间的关联。对于每个组件类型,都可以定义一个单件组件工厂来创建这个组件类型的实例。可以运用两种策略来实现这种关联:

        ·每种组件类型对应一个组件工厂。

        ·所有组件类型对应一个组件工厂接口。

        7.2)确定工厂将导出的功能特性。无论在实现活动7.1)中选择的策略是什么,当指定一个特殊组件工厂的接口时,必须处理下列要点:

        ·可以有一个或多个不同方法用于创建新的组件。

        ·有一些方法可以用于发现现有的组件而不是为每次调用而创建组件。

        ·客户机能指定组件使用策略。例如,一个策略为某一类组件提供一个单件实现。另一个策略会确定是否期望某个组件持久地维护它的状态。

        ·支持组件的生命期管理是组件工厂接口的另一候选功能。例如,可以在组件工厂包含释放已有组件的方法。

        7.3)引入组件工厂发现者。随着组件类型数目的增长,会出现如何发现相关联的组件工厂的问题。解决这个问题的一种方法是定义一个全局组件工厂发现者。这个发现者会维护组件类型和它们的组件工厂之间的关联。

      8)实现客户机。客户机使用组件提供的功能特性,它们也可以作为这些组件的容器,为实现客户机,要执行下列步骤:

      ·首先确定它们需要哪个组件功能特性。

      ·标识哪些组件应合在一起,并确定哪些组件能使用其他组件。

      ·确定在客户机应该范围内是否存在一些子系统,这些子系统会在其他应用中使用,把这些子系统分离出来作为新的组件类型。

 

5.结论

优点:

      1)可扩展性:扩展组件的功能只需增加新的扩展接口,现有的接口保持不变,这样对现有的客户机不会造成不利影响,开发人员可以通过使用多个扩展接口,而不是把所有方法合并到一个基接口来防止接口膨胀(interface bloating)。

      2)事务分离。把语义相关的功能分组到独立的扩展接口。通过为每个角色定义一个独立的扩展接口,组件能为相同或者不同的客户机扮演不同角色。

      3)多态性。在不需要继承一个公共接口的情况下支持多态性。如果两个组件实现同一扩展接口,那么某一扩展接口的客户机不必知道哪个组件实际提供功能。类似地,多个组件可以实现相同的接口集,因而允许它们透明地交换组件实现。

      4)将组件和它们的客户机去耦合。客户机访问扩展接口而不是组件实现。因此在组件实现和它的客户机之间不存在(紧)耦合。

      5)支持接口聚合和授权。组件能聚合其他的组件,并像提供自己的接口一样提供被聚合的接口。

 

不足:

      1)增加了组件设计和实现工作。当扩展接口模式没有被透明地集成在某一编程语言时,组件编程工作是特别繁琐的。

      2)增加了编程复杂性。

      3)附加的间接方法和运行时开锁。

posted on 2012-09-10 08:56  汝熹  阅读(459)  评论(0编辑  收藏  举报