关于类间消息的讨论(2)

版权声明:可以任意转载,转载时请务必以超链接形式标明如下文章原始出处和作者信息及本声明

作者:xixi

出处:http://blog.youkuaiyun.com/slowgrace/archive/2009/04/26/4125076.aspx 

1、类间消息的传递

这篇博文里探讨了类间消息传递的3种方式,用在层次百分比的动态更新里我这么做:

(1)CDtlSfr:sngValue_BeforeUpdate中,CDtlSfr发出ValueChanged消息

(2)CDetailList:m_cmm_ValueChanged_S中,CDetailList收到消息后更改数据,并发送ValueChanged消息和DetailIdChanged消息

(3)CTreeData:m_cmm_ValueChanged_D中,CTreeData收到消息后传播数据更改,并发送ValueChanged消息

(3)CTreeData:m_cmm_DetailIdChanged中,CTreeData收到消息后更改数据

(4)CTreeCtl: m_trd_ValueChanged中,CTreeCtl收到消息后更改标签,之后发送SelChanged消息

(5)CTreeWnd:m_cmm_SelChanged中,CTreeWnd收到消息后更新显示,可能需要通知到CDtlSfr

现阶段我采用的主要是间接通知法,就是用第三方的cmm对象来传消息。上面的2、3、5都是用的这种方法。1和4是用的直接通知法,其中1是VB自带的事件、4是想试试Tiger_Zhao说的方法。其实我还想试试ahao说的控制范围的建议,就是不让所有的cmm都指向全局的gcmm,而是部分有个范围。比如树窗和它拥有的细节子窗体、树控件共同拥有一个模块级的cmm对象,这样相关的消息只在它们之间传递。不过这样的话,这3个类就要同时拥有两个cmm对象,以便同时接受全局和局部的消息。我先试试主打全局cmm吧,不行的话再采取ahao的方案。

2、绕死人不偿命:类间数据的传递

今天着手实现这个消息流程,发现类间传递信息可真绕。比如说:

(1)细节子窗体只知道自己的表名和当前的detailid,它发消息给CDetailList类,叫它更改value,这些信息倒也勉强够了。

(2)可是的话,当同树独改节点独改的时候,CDetailList加完新细节,它光告诉CTreeData类自己新添了条记录就不够了。CTreeData还需要知道倒底是哪棵树或哪个节点需要接受这个新的细节ID。

(3)如何知道当前用户关注的是哪棵树的哪个节点呢?一个办法是让CTreeData去找当前系统中活动的窗口的当班的TreeCtl的SelectedItem。还有一个办法是让这一系列动作的始作俑者CDtlSfr类在开始这个消息接龙的时候就设法获得一个对当前Cnd(CNodeData对象)的引用,并在消息接龙中传下去。

(4)我倾向于后一种方法。因为谁知道这个消息接龙的过程日后会不会变化啊,而最一开始得到的数据却能始终保证是准确地反应了用户的意图的。

(5)另外,发现CNodeData真是这个数据模型里核心的东西,甭管什么消息只有把它传到了,所有需要的信息就都可以从它的属性或扩展属性得到。想来这也不奇怪,本来这个系统的初衷就是管理和展示树状层次信息嘛。

(6)另外,CDtlSfr如何获得当前的CND?一个直接的方法,是它取它的父亲CTreeWnd的当班CTreeCtl的当前节点对应的CND。这样有点绕,最后我决定,在CTreeWnd里安排一个公共属性叫CurCnd,这样CDtlSfr可以通过它的m_twd(CTreeWnd)得到当前的CND。还有个耦合比较小的方法,是CDtlSfr向它的父亲发消息,获得当前CND,但是感觉有点没必要这么麻烦。这两个办法都是如下左图。还有个办法是如下右图,就是CDtlSfr向CTreeWnd发消息,之后由CTreeWnd负责通知CDetailList。有点想不清楚了。
先从CTreeWnd取CurCnd再发消息直接通过CTreeWnd转发消息

 

总之,感觉系统慢慢地又开始向一团乱麻的状态行进了:若干全局变量的存在、类之间的交叉引用、同一信息可以从多处得到等等,这些是让我觉得乱的诱因……

3、各司其职,请记住!!

睡了一个长长的极不香甜的下午觉,睡睡醒醒地、心烦意乱地想着这个消息链。感觉至少有一点不对了,就是各类的职责不对了,很多类在伸手管它不该管的事。

比如说,CDtlSfr嘛要知道Cnd啊,这关它NIAO事啊?上次Tiger_Zhao提醒的我怎么都忘了?它应该只知道DetailTable和DetailId,它的内容发生变化后,单纯的它应该向它爹汇报,而不是直接去通知什么CDetailList、还要搜集什么CNodeData。它应该只负责用户交互的。

再比如,它的爹CTreeWnd是老谋深算一些,知道自己拥有多个CTreeCtl,还知道其中哪个当班,但是他不应该知道CTreeData和CDetailList之间多对多的暧昧关系。它应该直接通知CTreeData,里面的蹊跷让CTreeData去处理吧。

同样的,CTreeCtl也不应该知道CTreeData和CDetailList之间那点儿事,它就只知道有数据变化的时候通知它的数据总管CTreeData就对了。

所以说,除了CTreeData,就不该有其它的对象给CDetailList发过消息,就像下图这样。

各司其职的类间协作

4、村里的小喇叭

(我可真能跑题,折腾了很多天API之类的东西。强烈BS自己。)

某天晚上失眠得到的灵感,又否定了上面的想法,记录一下。其实最好的类间消息的传递也许应该像村里的小喇叭。每当一个对象干完该它干的活后,它就嚷嚷一声:喂,我这儿的×××做完了,该接班的人快接班哈。它不用管该谁接班,同样的消息,程序员也许在这个版本需要木匠对象来接手这个活,也许下个版本或者另外一个业务逻辑需要石灰匠来接手这个活,也许需要这两种对象同时做出反应。都没关系。发消息的那个对象不需要做任何改变。

比如,CDtlSfr的数据发生改变。对于同挂全改的情况,只需要CDetailList接手就可以了;而对于节点独改同树独改,则需要CTreeWnd和CDetailList配合工作,因为它们各自拥有下一步的工作所需要的部分数据(见上面第2节的讨论)。比如,对于同树独改,CDtlSfr先通过CTreeWnd逐级通知到CTreeData,它会标记自己是否为同树独改的那棵树;同时CDetailList也得到消息,改数据,改完之后发消息说自己的value变化了,要同树独改;CTreeData这时早已准备好了,得到这个消息后,立刻就做相应的处理。

不过,这里有一点让我纠结,同树独改时,CTreeData和CDetailList得到消息貌似应该有个先后顺序,才能保证逻辑正确。可是如果有先后顺序的话,这又违背了小喇叭的初衷了。这相当于通过小喇叭广播消息的人还是得知道谁要接受这个消息,连先后顺序都得知道!

一个可能的解决办法,就是让可能接手的两个类自己协商。不管谁先接到消息了吧,就先把自己该干的活干完了,然后做个标记。后接到消息的那个对象,干完自己的活后,就检查那个标记,如果那个标记在就进行后续的工作。比如,同树独改时,如果CTreeData先接到消息,那就先标记自己就是参与同树独改的树,然后CDetailList改完相应的细节数据后再发细节改动数据给它,它收到这个消息后再进行真正的同树独改活动;如果是CDetailList先收到消息,那CTreeData先得到的消息就是细节改动消息,CTreeData就检查自己的标志,发现最近还没收到过关于同树独改的消息,那就先把细节改动的信息记下来,等到收到同树独改消息时再干活。

这里,CTreeData挺纠结的。它得知道这么多事儿。相当于关于同树独改的业务逻辑全封装在这个对象里了。唉,总得有个人扮演那个上有老下有小到砥柱啊。先酱紫吧。不然我太纠结了啊。

对了,这么一来,类间消息我基本上还是采用间接通知法了,说形象点,咱统一用“小喇叭”了。

更多树类文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值