博威---云架构决胜云计算

 找回密码
 注册

QQ登录

只需一步,快速开始

搜索
查看: 3519|回复: 3

白话面向智能体编程(Agent Oriented Programmig, AOP)之一

[复制链接]
发表于 2021-7-18 08:57:23 | 显示全部楼层 |阅读模式
不使用buzzwords说明AOP(翻译)- -

The Ted Neward Challenge (AOP without the buzzwords)

不使用buzzwords说明AOP


作者: Adrian Colyer

译者:flyingbug

英文原文

译注:

翻译这篇文章,不知是被其对AOP看法吸引还是其对AOP的描述方式吸引,总之这是AOP文章中看着最舒心的一篇。翻译的水平不高,为了不误人子弟,在上面配上了英文原文的链接,如果有不清楚的地方,可以原文对照一下。

TSSjava讨论会的AOP小组讨论结束后Ted Neward发出了一个挑战:"an explanation of AOP without resorting to buzzwords."本文作者Adrian Colyer接下了这个挑战,并写出了这篇非常好的文章,从设计角度清晰的说明了AOP解决了什么问题,而且没有用一个令我头大的诸如point cut等等之类的buzzwords(强意词?呵呵)

每天软件开发领域都会冒出各种各样新鲜的词汇,不知道其他人怎么样,反正我是经常头晕,记得曾经为Martin Fowleractive record头晕了N(Martin好像很喜欢造词@_@),我希望能多一些Adrian Colyer这样的高人,好让我等下辈不至于追随的那么痛苦。

以下单词和词组在后面的文章中将不会出现:scattering, tangling, crosscutting, modularity, encapsulation, abstraction, dominant decomposition, concern.


当编写软件的时候,一个好的想法是:能够将程序中的每一个想法、概念、需求等等只做一处实现.

举个例子,如果编写一个银行系统,银行帐户的概念可能有一个直接的表示,比如:BankAccount类。如果写一个医疗程序,病人的概念可能有一个直接的表示,比如:Patient类。一个设计上的概念指向一个实现结构。

现在考虑一个简单MVC程序。一个简单的设计层面的需求是:随着model类的状态的变化,所有注册过的view都要被改变-但是这样一个单独的设计需求却很难被设计到一个单独实现结构当中。在一个典型的实现中,你将看到notifyObservers()这样的方法遍及能够使model改变状态的方法中。这个实现背离了需求到实现一对一映射的目标,代之以需求到实现一对多的结构。

设计中的概念和需求可以看作软件演进的一个元素。设计中这个元素到实现一对一的映射使得设计可以容易的添加、删除和维护,而如果元素到实现的映射是一对多的将导致设计很难进行添加、删除和维护,因为需要很多地方更改相同的实现,并且必须保证对他们的更改是完全的和一致的。

在实际的软件系统中,开发者可能遇到最极端的需求到实现的映射是old chestnut, tracing。举个例子,一个设计描述“当trace被设为可用,那么所有方法的进入和返回都要记录在一个trace buffer。”在我经历过的一个系统中,一个单独的需求到实现的映射超过1:100,000。想象一下所有这些实现都要在维护和添加新功能时被更改。当面对这样的情况,大多数的程序员会使这个需求到实现的映射失效来代替修改。

在上面提到的系统中还有一个相似的例子,这是一个用日志来记录程序异常的需求-这个需求到实现的映射超过1:8,000。但是以上都是极端的例子,大多数情况下很难碰到这样巨大的比率。更普遍的情况是一个需求到实现的映射率大概在1:20或者1:30左右。上面描述的MVC需求一般都会在这个范围内。如果想找一个开源的例子研究一下,可以看看Eclipse JDT compiler编译部分的代码。

下 面让我们看看新的方式,你将看到更加巧妙的方法,就像一个类实现一个接口那样。我们仍然要保持需求到实现一对一的清晰的映射,但是在很多情况下,一个类会 用它的方法和状态的一个子集来提供对一个接口的实现,但这是不够严密的。需求虽然被定位到一个实现,但是这个实现的边界是模糊的。据我所知,许多程序员通 过把关于这个接口的实现的方法集放在同一个源文件来实现定位,并且在很多情况下这是一个很不错的方法。在这里我想做的是,描述当你开始努力得到一个需求到 实现的一对一的清晰的实现时可能会遭遇的情况。

现 在让我们来看一看这个问题的另一面。我们要每一个设计上的需求清晰的映射到一个实现结构上。我们也要每一个实现结构仅映射到一个设计需求上。我们已经看到 一些设计上的需求需要在实现中展开,这就意味着在实现的某些部分是不可避免的必须处理多个需求。这就是需求到实现的多对一映射问题。再想想MVC的例子,model类正在处理至少两个设计上的需求:一个是描述他们的模型是什么,另一个是当他们的状态发生变化时通知每一个注册的View

这 种多对一的问题和一对多的问题一样麻烦。举个例子,它意味着当一个程序员修改一个类的时候,他必须意识到并且正确的处理这个类描述或使用的所有需求。经验 显示,在某些应用领域做这些工作是非常的麻烦,所以一些特殊的框架被发展出来为这种多对一映射问题提供通用的处理。一个例子是企业应用开发,在这个领域中 要求开发者首先必须对业务领域的问题非常熟悉,还要求开发者管理在业务领域的诸如:事务,数据持久和安全方面的需求。在设计中,包含业务逻辑和许多其他需 求的类是很难被重用和测试的(举个例子,你想得到模型类,却不得不把他们纠缠到其他不同的需求中)。

所以在真正的大型系统中,我们需要面对的不是需求与实现间一对一的映射,而是多对多映射。这就是为什么软件如此难以维护,难以理解并且如此复杂的原因。这不是开发人员的错,OO语言提供的能力和方法使我们不能得到一个设计需求到实现结构的清晰的映射(在本文中我们已经看到了几个这样的例子),因此我们看到的例子没有一个是实现结构清晰的映射到设计需求上。而这正是AOP尝试解决的问题。它使我们能够尽可能的接近一对一映射的目标。AOP通过加入一个新的称作方面的概念来解决这个问题,方面使得针对设计上的需求可以保存在一个地方,像上面提到的MVC中的view通知需求,这是OOP所无法做到的。

当你开始学习AOP,我希望你不仅把它看作现有软件的一个辅助手段,而且也是软件设计和实现的一个完整的部分。这也是为什么AspectJAOP的概念直接集成到一个语言中。请记住,我们需要一个设计和实现的一对一的映射,并且无论何时,我们向任何方向偏离这个比率都会是我们陷入麻烦。AOP是最能使我们接近一对一这个目标的编程方法。



Adrian同志有一篇关于Aspect Oriented Programming的Blog The  Ted Neward Challenge (AOP without the buzzwords),俺非常的喜欢。这篇文章中文翻译过来可以是“无废话AOP”,它从一个脱离了具体实现手段的视角,用简单清晰的语言向我们表达了Aspect Oriented Programming的本意:尽量将需求和实现的关系由1:N逼近至1:1。俺也非常希望能整出这么一个“无废话Agent Oriented Programming”,可是基于下面两点考虑,俺还是决定放弃:一个是Agent  Oriented Programming不光是个有意思的技术话题,还与学术界,理论界有很深的渊源。要“无废话”,且饶有趣味地阐述这样一个理论问题,是相当有难度地,还是时不时有必要来点废话,才不至于让同志们看得睡着过去。另一方面,记得上学的时候,老师传授的读书体验是先把书读厚,再把书读薄。书读薄了,吃透了,归纳出来,写出来的都是精华,当然也就无废话;而俺现在还处于把书读厚的第一阶段,所以写出来废话会比较多一点。基于这样的考虑,这个系列的文章可以被称为是“白话Agent Oriented Programming”。

如果俺有足够的耐性把文章全整出来and您有足够的耐性看完所有文章,您会对以下的内容有一个大概的了解:

l 什么是Agent和Agent Oriented ProgrammingAgent这个概念并不是空穴来风,在理论界对它的研究已经很深入,Agent是Object的进化版本,进化的目的是为了让软件系统更贴近现实世界。从程序设计的角度理解,可以认为Agent就是绑定了Thread的Object。

l 为什么要整这么个概念出来,这个东东和其他一堆泛滥的概念的关系是什么可以说搞软件的人,特别是搞平台软件的人,本质上都比较,整天琢磨着怎么更懒,如果有个东东可以让100行的代码压缩到10行,将设计,调试,维护的时间由1天压缩为1个小时,他们就会将这种方法拎出来,凑成一个概念。OOP,AOP,SOA什么的基本上可以说都是这么整出来的(戏言戏说)。

l 怎么样在.Net 平台上实现Agent Oriented ProgrammingAgent Oriented Programming是一种思想,与平台无关。但既然是准备贴在以微软技术为主题的博客堂上,为了以示尊重,还是选择在.Net平台上实现的比较好。

l 俺们设计的一个Agent SDK,及其一些蛮有趣的特性实际上这个Agent SDK是俺们设计一个工作流引擎的副产品。在给大家做演示的时候,这个SDK倒是比上层的工作流引擎更能引起大家的兴趣(除了胸闷还是胸闷)SDK部分地实现了Agent的一些特性,例如AgentMethod,TimerMethod,Sensebility等。


l 未来之路这里的未来之路包含两个意思。一层意思是,围绕着Agent Oriented Programming,还有很多高级的特性等待我们去实现,例如移动Agent,合作Agent等。另一方面,对于任何思想,技术而言,光掌握其原理,明白是怎么回事,是不够的,还是得运用到项目中,创造效益,老板才会高兴,才会去下力气去推广。所以俺们也要考虑如何将这么好的东东应用到实际的项目开发中去。



 楼主| 发表于 2021-7-18 08:57:37 | 显示全部楼层
Agent之前-Object世界

在说起Agent之前,俺们还有必要先敬拜一下Agent的前辈Object,因为Agent实际上是由Object“进化”而来的。这话说出来,可能有些读者同志不太高兴了,Object有什么不好吗?现在这么多复杂的系统,不都是基于OO的思想设计出来的吗?

然也,OO的确为提高软件开发效率做出了很大的贡献,但是在使用过程中,OO也暴露出了一些痒处:

痒处一:OO并没有对现实世界中的实体加以区分。

在OO世界中,所有的软件实体都是Object,现实世界中的一张发票和一为员工,映射到OO世界中都是一个Class。Class发票具有一些数据(日期,金额)和操作(效验,保存),Class员工也具有一些数据(姓名,职位)和操作(上班,下班),从映射的角度来看,任何现实世界的实体都是数据和操作的集合。但实际上,在现实世界中,发票和员工还是有区别的。区别在哪里呢?在于发票是一个物体, 而员工是一个有心智的实体。发票类的方法只能是被动地被调用,如果我们不调用,任何一张发票都不会自动的进行效验或者保存。而员工的方法调用与否,是由员工自己来决定的。今天生病了,  不高兴上班,上班操作就不会被执行,今天任务重,他就会自动执行加班这个操作。换句话说员工类的操作不是被动调用的,而是自发完成的。

这种只能被动调用和自发执行的区别,归结一下其原因,是因为员工具有自己的心智,而发票是没有的。传统的OO并没有引入这个区分,而这种区分的却失所造成的结果就是所有的操作都是被动地等待调用。虽然我们也可以引入计时器,或者多线程技术来模拟主动操作,但这种并不完全贴合现实世界的设计思路是不是让各位隐约感觉有些不爽呢。

痒处二:同步和异步被人为地剥离。

上面讲的是OO对有些东东没有区分,这点说的是OO对某些东东又多余地加以了区分。比如,现实世界中,老师对同学们说:“请把书翻到78页。”老师并不需要知道翻书这个操作对于同学们来说是同步操作还是异步操作,他并没有说“请把书同步地/异步地翻到78页。”换句话说,翻书这个操作是同步还是异步,对于调用者(老师)来说,是不需要知道的,同学们知道就OK了。但是影射到OO世界中,对于调用者来说,他在调用的时候,就必须知道是同步调用还是异步调用。归纳起来说,在现实世界中,调用方式这种知识,是被调用方拥有的,而调用方是不需要考虑的,但在OO世界中,这个知识由被调用方转移到了调用方。Something  is different。体会一下,这种差异会带来什么样的问题。

痒处三:无法自然地模拟现实世界中的感知能力(Sensebility)。

举个烧菜的例子来说明感知能力。老妈教俺烧菜的时候,常用的语法是:“当什么什么的时候,就怎么怎么样”。比如:当水烧开的时候,把肉放进去;当鸡块炸至金黄色的时候,捞出锅来。这就是感知能力的例子。鸡块作为感知源,它的属性可以发生变化;俺作为感知器,可以捕捉到鸡块的颜色这个属性的变化。如果鸡块的颜色由肉色转变至金黄色,俺就必须做出相应的操作/处理:把鸡块捞出锅来。

这种感知能力在现实世界中是非常普遍地存在的,然而映射到OO世界中来,却显的有些别扭。如果我们将鸡块和人构造为两个Class,要想人能感知到鸡块上某个属性值的变化,首先想到的是使用观察者(Observer)模式,在.Net平台下呢,则是在鸡块类中构造一个delegate,然后将人的某个操作挂到这个delegate上,当鸡块颜色值发生变化的时候,触发这个delegate。这种方式至少存在三个让人感觉别扭的地方:

l 鸡块就是鸡块,为什么鸡块这个Class里面要包含一个额外的delegate呢,这个delegate的存在对于实现鸡块这个class本身的逻辑来说没有任何意义,对于鸡块的逻辑而言,这个delegate是完全多余的,这还只是颜色属性上的delegate,不难想像,如果外界还有其他Class需要感知鸡块类其他属性上的变化,会有更多的delegate,更多的与鸡块本身逻辑不相干的代码出现。

l 注意到一个比较细节的问题。俺在看到鸡块颜色变为金黄色后,执行的操作是把鸡块捞出锅。这个“捞出锅”的操作,是由俺的心智来完成的,不是受鸡块的心智指挥,它自己蹦出锅来的。而在上面提到的使用delegate的解决方案中,我们把“捞出锅”这个操作挂载到delegate上,则“捞出锅”是由鸡块当前占用的线程来执行的,如果将线程理解为心智的话,则意味着是由鸡块的心智控制着人将自己捞出锅。是不是很诡异J 更直白地说法是:应该有一个线程来处理鸡块颜色的变化,另外再有一个线程来收到颜色变化的通知,并执行“捞出锅”的操作。这里有同志应该说了:也好办,把delegate的机制修改为多线程的就OK了!的确是这样,但需要注意的是要保持多线程机制对鸡块和人的透明性,如果因为需要贴近现实世界而增加Class的复杂性,那也违背了我们的初衷。

l 最后一个问题比较有意思。在现有的delegate解决方案中,我们只能针对实例(Instance)进行注册,而不可以针对类型(Type)进行注册。什么概念呢?比如锅里面有十个鸡块,俺得把“捞出锅”这个操作到这十个鸡块上依次注册一遍,才能保证每个鸡块在适当的时机被捞出来。是不是觉得和现实世界中的实际情况有些出入J 如果能够提供针对类型的注册机制,只要将俺的后续操作到鸡块类上注册一次,在感知范围内的所有鸡块,管他是十块还是二十块,都能被俺感知到颜色上的变化并执行正确的后续操作,这样会来的更简洁,更自然。

上面罗罗嗦嗦给OO挑了些毛病。实际上归纳起来就一句话:OO并不是对现实世界最贴切地模拟。而软件世界的终极目标是为了模拟现实世界,既然OO并不是最贴切的模拟,问题也就暴露出来了,改进的余地也就显现出来了。

   怎么改进?轮到Object的接班人Agent出场了。
 楼主| 发表于 2021-7-18 08:57:53 | 显示全部楼层
进入Agent世界-什么是Agent?

  在前面的讨论中,说道了一下Object让俺们感觉不是很爽的地方。总结下来:OO并不是对现实世界最贴切的模拟。那么什么东东可以比OO更加贴近地来模拟现实世界呢?就目前看来,还是Agent可以担当起Object接班人的这个角色。

这里多插一段话。俺们可以注意到,不论是Object还是Agent,他们都有比较深的理论渊源,同时以指导实际软件开发为其价值导向。目前在软件开发过程中,俺们大量地使用着Object的概念,所以前面讨论凡是涉及到Object的,俺们都尽量使用开发人员熟悉的语境来描述,比如同步方法,异步方法,.Net平台中特有的delegate等等。而目前围绕Agent的工作大部分还停留在理论研究或者实验室原型的阶段,所以在下面关于Agent的讨论中,理论学术(白话:纸上谈兵)的味道会略为浓一些。俺会尽量结合同志们熟悉的生活中的例子来解释这些理论上的东东。

俺们遇到的第一个问题是Agent的定义是什么?这其实是一个蛮无聊的问题,能够在纸上默写出Agent的定义并不代表这位同志已经深刻地理解了Agent的含义。但这里还是罗列一下前辈们给出的若干关于Agent的定义。从五花八门的定义中俺们也可以体会一下Agent这个概念所包含的内涵的丰富性。

1. The MuBot Agent "The term agent is used to represent two orthogonal concepts. The  first is the agent's ability for autonomous execution. The second is the agent's ability to perform domain oriented reasoning."
这个定义强调了Agent的自动执行能力和推理能力。

2. The AIMA Agent "An agent is anything that can be viewed as perceiving its environment  through sensors and acting upon that environment through effectors."
不知道给出这个定义的前辈是不是搞生物学的,怎么看Agent都像是由细胞核和一堆毛须组装成的原始生命体。

3. The Maes Agent "Autonomous agents are computational systems that inhabit some complex  dynamic environment, sense and act autonomously in this environment, and by doing so realize a set of goals or tasks for which they are designed."
这个定义比较复杂一点,他强调了Agent与外界环境的关系,也就是说Agent的存在是为了某个目的/目标而感知并且改变环境。在后面会介绍到,这是区分Agent和普通程序的一个重要依据。

4. The IBM Agent "Intelligent agents are software entities that carry out some set  of operations on behalf of a user or another program with some degree of independence or autonomy, and in so doing, employ some knowledge or representation of the user's goals or desires."
IBM给出的定义就少了一些学究味,多了些实用至上的气息。认为能够自动完成某种指定任务的软件体,都可以当做Agent。

5. The FAQ Agent [http://www.ee.mcgill.ca:80/~belmarc/agent_faq.html] "This FAQ will  not attempt to provide an authoritative definition ..."
老外搞笑起来,也是一流。

6. The Favorite Agent “An autonomous agent is a system situated within and a part  of an environment that senses that environment and acts on it, over time, in pursuit of its own agenda and so as to effect what it senses in the future.”
个人比较欣赏这个定义,纯理论的东西没功夫去搞,纯实践的东西没兴趣去搞,而这个定义试图在理论和实践之间找到一个平衡。

。。。

沿着探究Agent本源这个话题继续聊下去,眼前会出现好几条不同的脉络/线索。比较有意思的是那些搞人工智能的同志们,他们热衷于使用Agent的概念来拟合人的行为和思想,他们更愿意从生物/生命的角度来描绘软件世界中的Agent。所以他们使用了很多心理学上的术语/符号来刻画Agent,比如信仰(Belief),Intention(意图),义务(Obligation)等。这些同志的精神和境界是值得俺们尊敬和向往的,但作为大规模商业软件开发流水线上一枚微不足道的齿轮,俺更关心的是将Object替换为Agent后,代码量会节约多少行,项目工期会缩短多少天,这类和薪水/年终奖挂钩的实际问题。基于此考虑,俺决定选择一种相对比较practical的方式继续向同志们介绍Agent的概念。

Michael在他的论文Intelligent Agents:Theory and Practice中给出了一个Agent的弱定义(这还只是个弱的!强的就免了)。他说满足下面四个条件的东东,就可以称为是Agent:

l autonomy: agents operate without the direct intervention of humans or others, and have some kind  of control over their actions and internal state;
自治性,也就是下面俺们将要谈到的独立心智。

l social ability: agents interact with other agents (and possibly humans) via some kind of agent-communication  language;
社会性,这点俺并不认为是Agent的本质特性,一个独立存在的Agent难道就不是Agent了吗。一位生活在孤岛上的同志难道就不是Human了吗。之所以拎出这点来,俺估计Michael的考虑是:单个的Agent的存在是无意义的,只有处于群体中的Agent才能体现它的价值。

l reactivity: agents perceive their environment, (which may be the physical world, a user via a graphical  user interface, a collection of other agents, the INTERNET, or perhaps all of these combined), and respond in a timely fashion to changes that occur in it;
反应性,能够接受外界的输入信号,并且做出相应的反应。

l pro-activeness: agents do not simply act in response to their environment, they are able to exhibit  goal-directed behaviour by taking the initiative.
主动性,或称目标驱动,这是Agent很重要的一个特点。依据当前的环境和自身的心智,Agent 可以主动地执行某种操作或者任务。举例来说,大家都熟悉的Web Service,不论Web Service能够提供多少服务,计算能力多么强,它都不是一个Agent,因为它是被动地,而非主动地提供服务。

上面罗列了一堆Agent的定义。俺们除了敬仰前辈大师之外,还可以尝试着归纳一下Agent的本质。定义可以传递给俺们的信息是:什么是Agent;而本质可以传递给俺们的信息是:什么不是Agent。从这两个角度来把握一个概念,基本也就八九不离十了。

Agent的本质是什么?个人观点:拥有可以与外界交互的独立心智。

解释一下这句话的含义。这句话包含了两个层面的内容。

一)独立心智。心智是什么?心智就是逻辑,由百万个判断语句组成的复杂逻辑是心智,一个if语句,甚至一个顺序执行语句,本质上来说也是心智。说到这里有同志会觉得不对劲了,如果心智就是逻辑的话,那么MIS系统中的发票类也是具有心智的啦,发票类里面也包含有逻辑代码嘛,而且还蛮复杂的呢。对的,发票类是具有逻辑,或者称为心智,但是他不具有独立的心智,什么意思呢?发票类中的逻辑是否执行,何时执行,不是由发票类自己决定或者控制的,这点很重要。比如,发票类有个逻辑(Method)可以将自己序列化为一段XML,当外界调用发票的这个Method的时候,发票是不可以说,“俺正烦着呢,待会再给你序列化”,发票的序列化操作会被立即执行,而且是无条件的。所以说发票类并没有独立心智,因此发票类是不可以视为Agent的。

二)与外界交互。交互这个词用得涩了点,其实白话就是输入输出,能够捕获/感知到外界环境的变化(输入),并且做出相应的反应(输出),就OK了。从这个角度来理解,如果一个东东,它慧根再怎么发达,再怎么我行我素,但自我封闭起来,不接收外界的任何信号,也不对外输出任何信号,那它也不可以称为是Agent。这里有同志也许会说:“同学,这个定义条件未免太弱智了点吧,你倒是找一个完全封闭的软件出来俺我看看啊”。俺还真能给你找一个出来。注意到的是“交互的”,这个相应的意思是根据外界的条件,输出是可以变化的。写一个简单到只包含一行语句的程序:Console.WriteLine(“Hello  Agent”);。不管外界是刮风下雨,不管机器是386还是X86,不管内存是256M还是2G,只要这个程序执行,它的输出就是”Hello Agent’。这个程序的确是有输出,但不是根据输入而得到的“相应的”输出。所以这个只包含一行代码的程序并不是Agent,它只是一个Program。

关于Agent的本源,其实是仁者见仁,智者见智的一个概念。俺在这里白话一番,基本上是起个抛砖引玉的功效,并不是讲这就是绝对正确的。针对不同的背景,环境或者应用场合,俺们可以将Agent的本质理解为不同的东西。最重要的是,理解深刻了,领悟透彻了,一定要能解决实际问题,一定要在实际开发中派上用场,否则就不是白话,而是白谈。

提供几个有意思的Topic供同志们消遣。

l 计算机病毒是Agent吗。

l 在以往设计的软件系统中,有没有见到过Agent的影子。

l 什么样的软件系统,Agent最能派上用场。
 楼主| 发表于 2021-7-18 08:58:10 | 显示全部楼层
前段时间一直周旋于各种有趣且辛苦, 或者无趣且更辛苦的事情当中, 虽然其间也切换到其他好些不同的技术领域, 但一直没有放弃在AOP方面的关注思考. 前面之所以没有能接着AOP这个话题继续和大家聊下去, 是因为感觉自己没有足够的精力和空闲来将这些想法沉淀下来, 并回锅为简单直白, 易于消化和理解, 并能引发思考的东西. 这几天, 出差在外, 工作之余免去了灶台内外的忙活. 油烟味少了, 人也觉得清爽许多; 闲暇多了, 就免不了想爬爬格子. OK, 闲话到此为止,  就让我们继续AOP的白话之旅吧J

简单回顾一下前一段旅程(一,二,三),  在前面我们简要介绍了什么是Agent, 这个东东的来由, 以及与其他重要概念, 如Object的区别. 如果说前段理论之旅展现的奇异风光令我们心神荡漾, 那么接下来的实践之旅就会又把我们拽回到繁杂而精密的软件世界中.

在前面也有介绍过, 目前好像还没有一个专门针对AOP的IDE, 这对于急于操练一把AOP的同志来说是个不大不小的尴尬. 不过好在Agent也是由Object脱胎而来, 基于目前的OOP语言, 我们也可以来过一把AOP的瘾. 这里我们选择的是.Net 平台下的C#. 为什么要选择C#,,,, 因为如果使用Java, 文章也就不会发在这里, just jokingJ 理论上说, 任何OOP语言, Java, Delphi, C++, 都可以作为哈里.波特同学手中的魔法棒,  点化出妙不可言的Agent. 之所以选择C#, 是看中他的优雅和简洁(补充一句, 直到现在俺依然固执地认为Delphi是最优雅的语言, 虽然Borland迫于生计不得不出售整个IDE部门, 但俺依然决意守望Delphi, 直到Delphi的桅杆没入海平面的最后一刻…)

翻翻讲述Agent理论的书籍就可以查到, 一个为理论界所接受的Agent需要具有如下若干特征:

l 代理性(Action On Behalf Others)

l 自制性(Autonomy)

l 主动性(Proactivity)

l 反应性(Reactivity)

l 社会性(Social Ability)

l 智能性(Intelligence)

l 合作性(Callaboration)

l 移动性(Mobility)

My god! 光把这些名词理解一遍就让人头大了. 不多解释了. 简单点, Simple is good. 我们现在不需要迎合理论家挑剔的口味, 只需要创造一个具有不完全特性的Agent. 女娲同学造人的时候还不是就地取材, 捧着坨泥巴就捏上了J 另一方面, 作为整个AgentWorld的缔造者, 我们必需意识到这样一点: 上述这些特性, 是分层次的, 比如反应性, 和自制性, 这应该是位于Agent心智(Mind)最底层的特性; 而社会性, 智能性,  合作性等, 则应该属于Agent的高级心智, 需要其他心智能力的支持. 在由混沌到开天地的最初步骤中, 我们只需要实现最低层次的Agent心智即可.

综合以上考虑, 在我们捏出的第一个Agent身上, 可以看到如下几种心智:

l 同步异步的统一和同类群组

l 对外界变化的感知

l 时间驱动

l 移动性

下面我们来逐一审视这些貌似简单, 却可能蕴含无限组合及演化能量的心智要素.

同步异步的统一和同类群组

前面聊到说, 我们有认识到Object世界存在着”同步和异步被人为地剥离”的尴尬, “同步异步的统一和同类群组”则是Agent世界对这一尴尬的解答. 在我们的Agent世界中, Agent A1呼唤Agent A2协助其做某件工作M1, 并不需要了解到A2做这件事情是同步在做还是异步在做, 这是同步异步的统一; 更进一步, 如果这件事情, 和A2具有同样能力的好几个Agent都可以来做, 那么A1更不需要知道到底是哪一个具体的”A2”在做这件工作. 有点抽象噢?  Ok, 这好比现实生活中的一个例子: 领导曰”上午10点让司机过来接我去开会”. 领导作为一个Agent, 他不需要了解司机这种Agent 10点开车到楼下是同步行为还是异步行为(当然司机自己要清楚), 也不需要了解开车过来的是单位上的哪个司机, 小王or小张? 这是领导需要关心的事情吗? 他只需要知道10点下楼, 就有个司机在那候着. 用程序语言来描述:

Boss的执行代码就是:

driver.ComeHere(10:00)
Driver的代码:

class Driver : Agent_XXX
{
  [AgentMethod(AgentMethodCallMode.Asyn, AgentMethodRouteMode.Group)]
        public virtual void ComeHere(DateTime time){…}
        …
}
Ok, 让我们把所有注意力都集中到蓝色的Attribute上, 这是Driver这个Agent类在”同步异步的统一和同类群组”这种心智上的体现. 为什么我们刚才说要选择C#这种优雅的语言, 就是因为我们可以使用Attribute这个特性来将Agent的心智附着在普通的Object Class上. 当然, 我们也可以额外地用一个描述心智要素的XML文件来和Class绑定, 但个人感觉而言, Attribute来的更加优雅直接一些.

AgentMethod, 这个属性表明, ComeHere这个Method, 是Driver这个Agent的一种能力, 注意是能力不是心智. 这种能力带了特定的心智信息:

l AgentMethodCallMode.Asyn
这个Attribute表明这种能力是异步调用的, 而非同步. 看到这里有些同志不免生疑, 不是说同步和异步不再区分的嘛, 怎么还有Asyn, Syn这样的标记呢? 不爽! 解释一把, 我们所说的同步和异步不再区分, 是从调用者的角度考察, 比如领导之于司机, 老师之于学生. 而对于方法的被调用者, 也就是实际执行者来说, 他当然是需要”内心”里知晓这个方法到底是如何完成的. 实际上在领导调用driver.ComeHere(10:00)之后, 领导所拥有的心智, 即线程马上可以接下去做其他事情,  而ComeHere(10:00)这个方法, 则被转移到某个Driver实例的心智, 即线程上去执行.

这里的一个小小差异, 实际上凸现出Agent和Object的一个很大区别: 在Agent世界中, 每个Agent只需要关注自己逻辑是如何执行的, 而对其他Agent的逻辑执行细节的关注, 被降低到的最低.

如果有同志觉得上面这段话过于抽象, ok, 让我们更技术化的语言重复一次: 每个Agent都带有一个独立的线程(我们可以把它理解为Agent的灵魂J), 每个Agent自身的能力(在OOP语言环境下被映射为Method)都在这个线程上来被解释和执行. 如果一个行为序列包含有若干不同Agent的能力的执行, 那么完成这个行为序列就会使用到好几个不同的线程, 并且线程之间的切换是完全透明和自动的.

深入到技术细节之后, 让我们赶紧上浮到更宏观的一个层面上来, 否则很快就会在对技术细节的探究中失去对Agent设计理念的把握能力. 现在我们已经知道: 一个Agent, 它所拥有的能力(也就是各种Method)只能由它拥有的灵魂(也就是其独占的线程)来执行. 那么显然的一个问题是: 这带来了什么样的益处?



l AgentMethodRouteMode.Group.
这个Attribute表明Boss要一辆车, 这个请求, 是一个群组请求, 而不是针对某个Driver类的某个具体实例. 这个请求会被放到一个基于群组(也就是具有共同能力的一类Agent)的请求池中, 假设此时单位有三位司机空闲, 那么其中的一位就会接受到这个请求, 随后执行之. 这应该是对Agent理论中黑板模型的一个最最简单的实现: 有什么请求, 写到一个黑板上, 有能力响应这个请求的, 就来处理, 并把这个请求从黑板上擦掉.

大家可以想像一下这种心智的用场何在. 先往现实世界中靠, 找找现实世界中是否存在这种例子? 大量存在, 银行柜台业务, 超时购物结算. 再回到软件世界中, 我们很容易联想起一个词: 负载平衡J 如果具有某种能力(能够执行某种关键业务操作)的Agent通过Mobility心智(稍后会介绍方面内容)分布在整个系统的若干台不同机器上, 同时共享同一个群组请求池, 外部进来的业务操作请求进入请求池后, 就会为不同机器上的Agent所处理. 负载平衡乎J 当然, 谁说现在银行系统不是负载平衡的? 我们这里强调的是: 在Agent世界中实现负载平衡的简洁性.  仅仅需要一个Attribute, 并且, 由于底层的群组请求池是系统自动构造的, 因此如果需要进一步平衡负载, 只需要多new几个 driver, 并把他们移动到不同的机器上, 就好比银行里看到排队的人多了, 临时增加几个业务窗口的道理一样. 很重要的一点, Agent世界里能实现的, Obejct世界或者汇编世界里同样都可以实现, 我们看重的是实现的简洁性(偷懒性?)及于现实世界贴近的程度.



AgentMethod还有好几种组合, 这里就不一一介绍了, 陷入编码细节的讨论必然会妨碍我们对概念整体上的把握. 但这里不得不说明的是, 假设Boss需要driver在达到之后通知他一下, 应该怎么实现呢? 由于OOP的限制, 我们不得不使用一种相当不优雅的方式: 回调函数, 来解决这个问题.  于是乎, 在Boss这个Agent类中会出现如下代码:

[CallBackMethodAttribute(typeof(driver), "ComeHere")]

public virtual void CallBack_Driver_ComeHere(Message_ResultOfASYNCallMethod message){…}

这里的CallBackMethodAttribute表明, 当某个Driver达到楼下后, 会自动(对于Driver和Boss来说都是透明的)调用这个方法. 注意, 这个方法的执行, 是在Boss的心智中, 而不是由Driver来完成的, 也就是说, 系统会自动在Driver的线程中执行ComeHere操作, 随后又自动切换到Boss的线程, 来执行CallBack_Driver_ComeHere. 想像一下, 为什么会这样 and 为什么要这样? J



要不今天咱们就整到这里, 如果大家有兴趣的话, 下面的章节中, 我们会接着聊聊感知力, 时间驱动, 移动性等更好玩的话题. 整点小思考题, 注意到Agent类的每个方法上都带有virtual指示符,  why? 借用Matrix中的一句话:”There is something different.”, 其实, 刚才咱们所聊的所有内容, 包括今后旅途中所看到的Agent  World中大多数风景, 都位于水平面之上, 而顺着这个隐秘的线索深入下去, 您就能触摸到Agent  World位于水平面之下庞大而精密的支撑架构. 水面之下, 没有任何风景, 只有高速运转的调度线程, 吞吐繁忙的缓冲池, 张合有序的读写锁, 以及无处不在的BugJ
您需要登录后才可以回帖 登录 | 注册

本版积分规则

小黑屋|手机版|Archiver|boway Inc. ( 冀ICP备10011147号 )

GMT+8, 2024-5-5 10:45 , Processed in 0.686643 second(s), 16 queries .

Powered by Discuz! X3.4

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表