消息编程改变了传统编程的规则,以往我们通过对象的实例句柄来操纵对象,现在我们的对象有了名字,我们通过对象的名字去与对象互动,以往我们直接执行对象的方法,现在我们通过给对象传递消息由对象自己执行。
我们已有许多完善、实用、现成的各种工具类,我们不可能用消息编程的理念而重新开发这些工具,因此用消息对象包装现有的各种工具类是非常必要,而且必须的。
将传统的类改造为消息对象非常容易,用简单的对象组合模式。
现在我们假设一个传统对象 classA ,它有两个公开方法 m1(string param1,string param2),m2()。以往我们使用对象的方式如下:
classA aobj =new classA();
aobj.m1("p1","p2");
aobj.m2();
用消息对象包装后这样的:
public class newcalssA extends TLBaseModule {
private classA aobj ;
public newcalssA(){
super();
}
public newcalssA(String name ){
super(name);
}
public newcalssA(String name , TLObjectFactory modulefactory)
{
super(name,modulefactory);
}
@Override
protected void init() {
aobj =new classA();
}
@Override
protected TLMsg checkMsgAction(Object fromWho, TLMsg msg) {
TLMsg returnMsg=null;
switch (msg.getAction()) {
case "m1":
m1(fromWho,msg);
break;
case "m2":
m2(fromWho,msg);
break;
default:
}
return returnMsg ;
}
private void m1(Object fromWho, TLMsg msg) {
String param1= (String) msg.getParam("param1");
String param2= (String) msg.getParam("param1");
aobj.m1(param1,param2);
}
private void m2(Object fromWho, TLMsg msg) {
aobj.m2();
}
}
原对象成为新对象的内部属性,原对象的方法变为内部方法,只能由该对象内部执行。这时我们这样使用对象:
1、首先将对象加入工厂配置中,对象的创建由工厂负责。我们给对象起一个名字 mynewClass,以后通过这个名字来访问对象。
<module name="mynewClass" classfile="newcalssA" />
2、使用时我们先建立消息指令
TLMsg amsg =new TLMsg();
amsg.setAction("m1").setParam("param1","p1").setParam("param2","p2");
或 :
TLMsg amsg =createMsg().setAction("m1").setParam("param1","p1").setParam("param2","p2");
3、将消息发送给对象
putMsg("mynewClass",amsg);
消息对象接收消息后,自动解析消息中的action而执行相应的方法。
这样将一个传统的对象包装成消息对象,而具有消息对象的一切特征了。
以往我们直接执行对象的方法,现在通过消息来间接执行,似乎多次一举,降低效率。其实不然,由于有了消息对象的特征,我们可以灵活的控制、运行。举例如下:
1、以往我们要将对象实例化后才能调用,现在可以通过名字“mynewClass” 来标称对象。任何地方都不需实例化了,用名字就可。例如对象B(前提B也是消息对象)也使用它,那么对象B直接putmsg(“mynewClass”,msg)即可。名字是方便传递、存储的,而对象内存句柄很难。配置文件中也很简单,直接写对象名字。
2、应用更加灵活
例1:
上面以往我们代码中直接执行方法aobj.m1("p1","p2");过段时间如果想在执行该方法前调用对象C的一个方法action1,根据C的结果来判断是否继续执行,或者通过C的方法来过滤参数p1,那么我们必须来改代码。现在,我们可以通过多种方式灵活的实现:
——在mynewClass的配置文件中增加消息前期处理
<beforeMsgTable>
<action value="m1" >
<msg action="action1" destination="cobj" useInputMsg="false" usePreReturnMsg ="false" />
</action>
</beforeMsgTable>
那么,在执行m1方法前自动执行cobj的action1,我们无需改代码。 <beforeMsgTable>项中可以加许多执行消息项。同样我们也可以增加消息后期处理,m1方法执行完后继续执行其他的方法。
—— 通过消息链
我们先形成个消息l来执行C的方法 ——cactionmsg,然后将执行m1的消息附加在后面 cationmsg.setNextmsg(amsg),然后传送给对象, putMsg("mynewClass",cactionmsg),这样对象先后执行两个消息。
——我们不对外公布方法m1,在配置中配置消息路由链表
<!-- 消息路由表-->
<msgTable>
<msgid value="m1msg" >
<msg action="action1" destination="cojb" />
<msg action="m1" />
</msgid>
</msgTable>
上面配置中,消息链表表明消息id为"m1msg"的消息包含两个消息。其他对象发送设置了消息id(方法 msg.setMsgId("m1msg") )的消息给对象,对象自动根据消息id匹配相关的消息链而依次执行。
例2:
以往对象的实例化后,它的初始化行为是固定,例如实例化后它执行 myinit(),我们没法改变。现在我们可以在配置文件中增加初始化消息表
<initMsg>
<msg action="m2" ></msg>
<msg action="getuser" destination="user" ></msg>
</initMsg>
这样对象模块初始化后,自动执行自己的m2方法,然后执行对象user的getuser方法。运行更加的灵活。
例3:
对象自动继承了父类消息对象模板的一些系统功能,例如动态重载配置,重新加载模块等功能
例4:
以往如果我们想异步执行对象的方法比较麻烦,例如想异步执行上面对象的m1方法,首先我们要建立了线程类对象,然后在线程类中实例化A对象,执行A的方法。如果方法结果返回,则要传入回调函数或对象。可以说代码一大堆。现在我们非常简单的完成,因为我们的消息类TLMsg自带异步标志,只要我们对上面的消息设置下异步标志即可 amsg..setWaitFlag(false),同样的发送给对象 putMsg("mynewClass",amsg) ,则对象自动启动一个线程执行m1方法。在发送给对方消息时,我们已经自动将自己的对象实例句柄带人方法中,m1(Object fromWho, TLMsg msg) ,fromWho为调用对象实例句柄,因此可以方便返回结果。任何消息,无论是初始化消息表还是上面加的前后执行的消息,只要设置了异步标志,就自动异步执行。
例5
包装了消息对象后,由于只有两个public方法,既putmsg和getmsg,那么对象更加的独立,减少了依赖、方便了对象之间的解耦。对象的方法都是内部执行,对于对象的内部改变不影响其他对象。
例6
以往任何人都可以实例化对象而执行它的方法,例如上面只要我们实例化对象A后就可以执行aobj.m1("p1","p2")。也就是被执行者无法选择执行者。现在我们重新包装后的方法 m1(fromWho,msg),传入了执行者fromWho,那么我们就可以对执行者检测,看其是否有执行条件,同时,在消息TLMsg中也有创建者的信息。
例7
我觉得这是很重要的一点,现在我们包装的消息对象不仅可以执行自己的原有方法,还可以传递消息,起到消息路由功能。这特别适合一些消息接口或者消息网关,如我web框架里的urlmap映射模块或者Web服务接口模块。下面是我服务端对app客户端一个接口配置:
<msgTable>
<!-- client的msgid 对应的服务msg-->
<msgid value="postInfo" >
<msg destination="infomationControl" action="postInfo" />
</msgid>
<msgid value="usersinfo" >
<msg destination="infomationControl" action="queryByUserid"/>
</msgid>
<msgid value="queryInfoById" >
<msg destination="infomationControl" action="queryInformationById"/>
</msgid>
<msgid value="getReply" >
<msg destination="infomationControl" action="getReply" />
</msgid>
<msgid value="postReply" >
</msgTable>
app客户端传递来的json数据中包含消息id,服务端接口自动根据消息id传递给相应的执行模块。
总之 ,将对象消息包装化后,不是简单的调用方法的改变,更丰富了它的功能,也更加的灵活。