1.5 Agent与组件的对比
近十年来,AOSE的创建和进一步发展已经将Agent提升为一种开发复杂软件系统的新方法。借助于AOSE,开发人员可以拥有Agent的灵活性和强大的表达能力,以帮助管理软件生命周期,从而改进最终软件产品的质量。在AOSE的短暂历史中,其研究焦点经历了一次重要的变动:最初它仅仅用于提供构建基于Agent系统的方法学和工具;现在却更侧重于了解基于Agent的方法可能给传统软件开发所带来的特征变化。研究焦点的变动并不是无足轻重的,它对应于在软件生命周期中采用Agent技术的不同原因。
前者是在实际软件生命周期开始之前,选择Agent作为开发的基本抽象。做出这样的决定是由于软件生命周期之外的原因,一般是根据系统的本质或所处理问题的复杂性。如Tropos方法(Bresciani等,2002)所建议的那样,在整个生命周期中(从早期的需求分析到系统的结束)采用面向Agent的思想,选择Agent作为基本的开发抽象。这种方法的一个主要缺点就是,经常难以找到合适的理由来选择Agent开发常规系统,如文字处理软件和财务管理系统。这也是后来的AOSE方法在需求分析和需求确认阶段之后(或在此期间),转而确定为什么要采用Agent技术。开发人员并不需要被迫采用Agent来实现他的系统,而是可以集中于需求分析,然后派生出后续设计。这种方法的主要缺陷在于,开发人员或许不能利用Agent的一些有趣特点,如突发行为和泛化,因为太多的注意力被放在了直接来自于客户的具体要求。后者强调了开发人员应该了解何时及如何优先采用Agent技术,从而取代传统的、更加成熟的技术,如面向对象技术。
自从在1997年第一次发布FIPA规范(参见http://www.fipa.org),研究人员清楚地了解到使用Agent作为软件组件的可能性。它能够带来很多有趣的特征,如自治推理和目标导向行为。另外,FIPA选择CORBA接口来实现Agent之间的通信,这就更加强调了这些抽象之间的强相互关系。对于Agent和对象之间的区别存在着长期争论,(Wooldridge,2000a)就起源于这个比较,但这种争论有时是毫无意义的。
面向组件的软件工程提出了“扩展对象”的思想:通过组件的组装来实现复杂系统,满足对可重用模块的强烈需求。现实中的案例包括Web服务(http://www.w3.org)、CORBA (Suhail,1998)、JavaBeans(http://java.sun.com)和.NET(http://www.ecma-international.org)。这些组件可以跨越不同的网络、语言和操作系统,在系统开发中给予开发人员最大的自由。然而,面向组件的软件工程长期追求的目标并不会随着可重用软件单元技术的实现而终结,它还要考虑以下要素:
(1)商业现成(Off-The-Shelf,OTS)组件,即公开市场上可获得的组件,可以通过装配来创造具有附加值的系统。系统的质量和费用基本上取决于每个商业组件的质量和费用。市场会在提高可用组件质量的同时降低成本。
(2)自动组装,即通过使用自动化技术来降低组件装配过程的费用。组装过程的质量和费用直接依赖于自动装配所采用技术的质量和费用。
一个基于组件的系统,其费用包括各个相关组件的直接投资与自动装配技术的费用,商业组件和自动装配的结合使用可以降低费用总和。同样,系统的质量随着单个组件质量和自动装配技术的提高而提高。
Agent和组件的比较如表1.1所示,在表中展示了组件和Agent的一些重要方面。更加精确地,我们考虑了Agent元模型的重要特征,并将它们与组件元模型的相应特征做了比较。为了使结果具有最大的通用性,我们避免考虑任何特殊的元模型,如微软组件中的.NET元模型或Agent组件中的SMART框架(Luck和d'Inverno,2001)。
表1.1 Agent元模型和相应组件的特征
1.状态表达(State Representation)
Agent和组件都是包含状态的抽象,但它们采用了非常不同的手段来对外部世界描述和展示状态。组件的状态包括一组属性和一组与其他组件之间的关联。属性和关联可能是公开的,即其他组件可以直接操作它们。每个Agent都有思维状态,一般采用如下要素进行表示,如它所知道的(如信念)和它当前所追求的(如意图)。表示执行状态的模型之间所具有的主要区别如下所示:
(1)一个Agent无法直接操作其他Agent的状态,但是可以通过通信来影响它;
(2)Agent对于它们的目标有一个明确的表示;
(3)Agent对于它们所处的环境,以及环境中的其他Agent,有着明确的认知;
(4)除了唯一识别符,Agent没有公开属性。
Agent方法的一个主要优势在于:可以采取通用的推理技术来支持推导和“手段—目的”推理。相反的,组件的状态属性和关联不是在一个逻辑框架中构建,因此难以使用通用技术,必须在组件方法中对推理规划过程进行明确编码。
2.通信(Communication)
Agent和组件之间的主要区别在于它们所采用的通信机制。Agent使用发布性的Agent通信语言(Agent Communication Languages,ACL),而组件则使用元对象协议(Kiczales等,1991)。在面向Agent的方法中,消息发送仅仅是发送者试图将部分思维状态传递给接收者。我们采取FIPA ACL作为一个代表性的例子:它定义了行为原语(即语义消息类型),可行的前提条件(要求发送者发送消息时必须是真实的),合理的结果(即为什么发送者要发送这条消息)。当Agent收到一则消息时,它可以断言前提条件对于发送者成立的可行性,并且设法实现相应的合理结果。这是一个相当拗口的表达方式:发送者希望接收者知道“发送者想让它了解前提条件成立的可行性和实际上造成的合理结果”。使用结构化ACL的好处:除了能够更加自然地交换目标表达式之外,还可以简化具备复杂交互能力的反应式Agent的开发。没有推理能力的反应式Agent能够利用ACL的行为原语作为触发器,用于激活底层交互协议的状态自动机。JADE(Bellifemine等,2001)(参见第9章)和类似平台提供了这样的机制。
在面向组件的方法中,消息发送是出于两个原因:第一个是为了直接操作接收者的状态。通信的使用违反了组件的自治性原则,自治性要求组件应该单独为它自己的状态负责。用于实现组件的大多数技术禁止对状态的直接操作,这样是为了尽量满足软件工程的目标,将组件间的耦合性降低到最小。发送消息的第二个原因是发送者可以强迫接收者为其执行一个方法主体,而不用明确地与接收者通信告诉它为什么这样做。这样,执行的责任就完全在于发送者,它负责保证前提成立,以及在方法的完全执行过程中可能引起系统其余部分发生变化。
3.责任委派(Delegation of Responsibility)
我们已经指出,不管是Agent还是组件,责任委派都是基于通信的,它们在责任委派方式上的不同也正好说明了通信模式的区别。在面向组件的模型中,发送者仅仅负责一条消息的可能结果,也就是说,除了“请根据我的职责这么做”之外,发送者并不需要对接收者说更多。严格来说,组件根本就没有向其他组件委派责任。在面向Agent的模型中,接收者仅仅负责它自己的个体行为结果,发送者还需要说明为什么它要请求这个服务。Agent所能执行的一个非常重要的通信行为就是将其目标之一委派给其他Agent,如通过FIPA“achieve”行为原语。这个特殊的通信行为,被称为目标委派,是Agent用来委派责任的基本机制。
组件的元模型并不包含目标抽象,只使用了任务委派。组件通过强迫其他组件执行动作来实现它们的(隐含的)目标;Agent或许通过将目标委派给其他Agent来实现它们的目标(明确地)。这也是为什么我们一般把面向Agent的通信模型称为“发布性的消息传递”:Agent可能告诉其他Agent想要它们做什么,但是却没有明确陈述怎么做。相反,“强制性的”消息则被用于面向组件的方法,因为组件不可能只告诉其他组件做什么,而不说怎么去做。
对于组件而言,仅仅使用任务委派可能是一个很大的局限,因为目标委派是一个更加通用的机制。首先,任务委派是目标委派的一种特例,被委派的目标采取形式done(a),a表示一个行动,就像是FIPA ACL中为了获取合理的结果所要求的原语;其次,任务委派或许会抑制优化。如假定组件S具有目标g,需要组件R执行a1和a2来实现它的目标;S会先要求R执行a1,然后要求R执行a2。虽然S的根本想法是实现目标g,但这两个请求并不耦合,R无法利用a1和a2之间的跨越性进行任何优化。如果S和R是两个Agent,而不是两个组件,那么S仅仅需要把目标g委派给R,然后由R来自主决定实现目标的方式,也就是说,它将决定如何执行a1和a2。这种方法通过目标g将a1和a2耦合起来,使R能够执行a1和a2之间的跨越性优化。
4.各方之间的交互(Interaction between Parties)
不同的通信方式影响着Agent和组件如何将自身向外部世界发布。组件使用接口来列举它们所提供的服务,告诉客户如何同它们建立联系。复杂的组件模型,会给接口配上前提和后置条件。面向Agent(Agent Oriented,AO)的方法没有采用接口方式,而是提供了能力描述符,描述了一个Agent能够做什么,也就是它所采取行为的可能后果,以及它如何同其他Agent进行交互。能力描述符和后置条件之间的主要区别在于,前者能够表示在完全执行一个行为之后,环境的状态如何改变。后置条件仅仅能够断言,在一个行为执行后,组件的状态如何改变,因为环境并不是组件元模型的一部分。
5.与环境的交互(Interaction with the Environment)
正如我们已经提及的,环境是Agent元模型的一个结构组成部分,却不是组件元模型的组成部分。Agent在一个能够获取知识的环境中执行,因为它是处于一定的上下文抽象中。Agent能够感知环境且从中接收事件。这两种情况都会使Agent的思维状态发生一定的变化,进而导致对环境的变化产生反应。这同面向组件的方法有着根本的不同,组件仅仅通过具体化的事件来同环境进行交互。组件可能对事件产生反应,仅仅依靠事件本身的具体化来构建关系。
面向组件的方法似乎比面向Agent的方法能够更好地执行封装:只有决定改变组件本身以对事件做出反应时,组件的状态才会改变。如果更加详细地考虑这点,就会发现面向Agent的方法也重视封装。Agent具有推理能力,为它们思维状态的任何变化最终负责。Agent的感知器对于它的思维状态有着直接的知识推动,这都是由推理来决定,思维状态依然保持封装。