我的类该怎样安排(续)——请ahao也进来

slowgrace 2009-03-16 07:10:50
加精
这个帖子里和zhao讨论了很多,zhao还有其他几位朋友给了很多很好的建议,准备把总体框架大改一下。

起初我只想加个NODE类。加它不光是因为我每次传一大堆标志位做函数参数传得我烦,还因为微软的node对象在treeview不可见时不能很好地判断自己的上下左右,至少它的parent会是nothing。前几天我勉强自己每次要取其他node对象的时候把相应的树的可见性toggle一下,但是这种toggle貌似会引起treenode的expand事件,搞的我的见光标志位也是一摊糊涂账。所以,折腾来折腾去我就想加个node类了。

之后ahao和我提到MVP等经典模式。我看了一下资料,感觉我原来设计的对象模型太简单,一个对象负责的东西太多,导致逻辑复杂,变更和维护都很累。所以,思量来去决定大动。具体设计如下:

1、总的思想
基本希望的样子是面向对象的,负责数据的和负责显示的分开,集合类和单体类分开,界面数据和核心数据分开。各司其职,通过事件机制来进行消息传递。

2、节点表和节点细节表
在描述具体的设计结论之前,先介绍一下节点表和节点细节表

一棵树下可能同时存在多种不同性质的节点,比如,在资源管理器的树中,同时存在文件夹和文件两种节点,它们各自对应不同的属性。如何在数据库中管理这些位于同一棵树下但具有不同数据结构的信息呢?

初步思路是,在节点表中设置strDetailTable和lngDetailId字段,存储节点对应的细节信息所在的表的名字和在其中的ID。即,节点基本信息在节点表中,节点细节信息根据不同的类型存在另外的相应的节点细节表中。这样要找一个节点的细节信息,只要到strDetailTable字段规定的表中找相应记录就可以了。相应的,删除节点的时候,要同时删节点表和节点细节表中的记录。

注意:节点表与树是一一对应的,有几种树就有几张节点表;而由于多挂节点的存在,节点细节表和节点表是一对多的关系,就是,同一细节可能在不同节点表里都存在相应的节点,在同一节点表里也可能存在不止一条记录具有同样的细节。

2.1.节点表的字段
1.lngNodeId
2.lngFatherId:记录它的父节点的节点ID
3.strDetailTable:该节点的细节表名
4.lngDetailId:该节点的细节ID
5.sngValue,用来记录本节点的所有子节点的金额之和;
6.sngPercent,用来记录本节点的金额占父节点金额的百分比。
7.strNodeComment

2.2.节点细节表的字段
a)lngId
b)strName
c)strComments
d)bytMultiGua:多挂计数
e)sngValue:仅当为基础节点时,才有该字段

3、类的安排
a)CTree类和CNode类。一个CTree类实例对应一个节点表,一个CNode类实例对应一条节点记录。CTree类包含由CNode类对象构成的集合。这两个类是界面数据类。
b)CTreeCtl类。负责界面工作。一个CTree类可能对应多个CTreeCtl类。
c)CDetail类。这个是核心数据类。负责细节数据的增删改。
d)CMsgMate类。消息使者类。负责触发各种自定义事件

4、数据的装载
和zhao讨论的一个重要分歧在于数据的装载,zhao建议所有数据一次性载入内存,之后对树的增删改都直接在内存上操作,之后根据情况再批量更新到数据库。我承认也理解这种做法在性能上的优越之处,不过对自己的内存不是很自信,毕竟我想用这个树类日积月累维护很多各种各样的数据。

另外,我感觉我的应用对性能其实要求不高。我的树的特点是很深(层次很多),起初的几层节点并不多,只到最底层的叶子节点(这些节点是日积月累的)会突然增多很多。用户交互的时候,一般一次是只看一个节点,或增删改移一个节点或有限的节点。这时候,即使我有频繁的数据库操作,哪怕是改一点点也要访问数次数据库,因为要操作的数据量小,我想在性能上不会有什么感觉的。

所以,我现在在数据装载方面的设计只部分采纳了zhao的建议。现在在这个模型里只装载了全部节点的部分信息,它们存在各个CTree的CNode列表里。而CDetail里是不存数据的,它只是负责直接对节点细节表操作。CNode类里也不是简单的对应于节点表里的一条记录,比如它还有节点名、节点多挂计数等属性,这些属性是从节点细节表里查出来的。总的来说,CNode类里存的是一些界面上常需用到的数据,我把它存在这个模型中,省得做一些动作的时候需要频繁访问数据库。

这样有些数据我存了两个地方:CNode列表里有一份、数据库里有一份。这和zhao的建议有点相似。不过,我在变动数据的时候,不是攒着到最后返回到数据库的。而是变动的时候一竿子捅到底,直接改数据库,同时更改CNode里的数据,保持它最新。我给自己的做法美其名曰,叫模型里只存界面数据,呵呵。

5 类之间的协作
当用户对树节点进行增删改之后,各个类之间协作完成相应的数据和界面变动。
a)以改节点名字为例。这种数据存在节点细节表里,其变动在界面上要影响到所有树。
i. 首先CTreeCtl得到消息,知道用户改了数据
ii. 然后CTreeCtl通知CDetail改数据
iii. CDetail改完数据后通知所有CTree这一变动
iv. 所有CTree改自己相应的Node的属性,并通知和自己关联的CTreeCtl
v. CTreeCtl得到通知后,做界面的变动
b)以改节点father为例。这种数据存在节点表里,其变动在界面上要影响到所有同名树。
i. 首先CTreeCtl得到消息,知道用户改了数据
ii. 然后CTreeCtl通知相应的CTree这一变动
iii. CTree改自己相应的Node的属性,并通知和自己关联的CTreeCtl
iv. CTreeCtl得到通知后,做界面的变动
c)以改节点Comments为例。这种数据存在节点细节表里,其变动在界面上不需要显示。
i. 假设用户是在细节子窗体变动节点Comments。那么直接改就可以了,不需要做任何事。
d)考虑同树独改的情况。上面讨论的其实都是同挂全改的情况,当节点独改和同树独改的时候,就不一样了,以同树独改为例。独改时需要拷贝新细节,并减少老细节的多挂计数,并且要改原节点的细节ID。前2件事由CDetail负责,后1件事由CNode负责。具体过程如下:
i. 首先CTreeCtl得到消息,知道用户改了数据。并通过用户交互,确定用户希望同树独改数据
ii. 然后CTreeCtl通知CDetail改数据
iii. CDetail得到通知后,做两件事
1. 拷贝制作新细节,并通知相应的CTree这一变动
2. 减少老细节的多挂计数,并通知所有CTree这一变动
iv. CTree得到通知后,改自己相应的Node的属性,并通知和自己关联的CTreeCtl
v. CTreeCtl得到通知后,做界面的变动


6 类之间消息的传递
消息使者类CMsgMate定义了许多事件,并提供许多public函数用于触发这些事件。当我需要在2个类之间传递消息时,我就在这2个类里都加入CMsgMate类型的成员变量,并在对象实例化的时候,让这2个成员变量都指向同一个CMsgMate实例。这样1个类的CMsgMate触发事件的时候,另外一个类的CMsgMate成员也能收到。

具体地:
i. CTreeCtl通知CDetail:这2个类的CMsgMate成员都指向同一个全局的CMsgMate对象。
ii. CDetail通知CTree:这2个类的CMsgMate成员都指向同一个全局的CMsgMate对象。
iii. CTree通知CTreeCtl:可以用全局的CMsgMate对象,也可以用CTreeCtl类里的with events的CTree对象。
iv. CTreeCtl通知CTree:这2个类的CMsgMate成员都指向同一个全局的CMsgMate对象。


大致的设计就是如上这些,对数据装载机制和消息机制感觉还是有点不是很清爽,恳请点评一哈。谢谢。
...全文
1654 128 打赏 收藏 转发到动态 举报
写回复
用AI写文章
128 条回复
切换为时间正序
请发表友善的回复…
发表回复
slowgrace 2009-03-24
  • 打赏
  • 举报
回复
结帖了,感谢zhao, ahao, aisac的耐心指点和讨论,也感谢modest, 瑶的推荐,也感谢各位帮顶的朋友。

我准备用TDD(测试驱动开发)的方法来重写这个树类,先给自己挖个大坑,拟在这个帖子里http://topic.csdn.net/u/20090324/07/83c21505-4032-42f7-a43d-4a7400889610.html实时播报开发的进程,感兴趣的朋友请移步来指点,谢谢。
iM臭皮匠 2009-03-24
  • 打赏
  • 举报
回复
这个类的始末我都看过了
但是我还是没理解
学习中~~~~~
slowgrace 2009-03-24
  • 打赏
  • 举报
回复
新的设计决定
(1)和树节点显示相关的数据载入对象模型,这些数据一部分在CTree的节点CNode里,一部分在CDetailList里的Detail结构里。与相应的数据表的设计相对应
(2)当用户通过用户界面改动数据的时候,一杆子捅到底,直接到数据库里改,改完再到界面上显示出来。
(3)类之间消息的传递:通过一个全局的CMsgMate变量进行。

解释
(1)用类还是用结构,前面有个讨论。最后决定CNode用类,因为想想自己看到的开源的扩充树类的代码都用了自己的Node类,我想这些前辈可能都是考虑过的,应该有它的道理;Detail用结构,这主要是心痒想试试zhao支的招,增加点见识。
(2)数据的变动没有像zhao建议的那样用内存标记。有2个原因,1则我觉得变动时我一般只操作有限的几个节点(常常是1个),所以这时候性能的差异估计可忽略;2则我还有细节子窗体用于显示细节相关的数据,有些数据在树模型里,有些不在,到时候一部分从内存取、一部分从树模型里取,还要保证数据一致性,感觉逻辑太复杂,维护性差。

要注意的:
(1)尽量通过消息的传递而避免直接调用类的公用方法来解耦;
(2)在实现数据变动相关的方法时注意封装,注意考虑日后也许会想转到zhao的方法时的可替换性。
quanna1129 2009-03-23
  • 打赏
  • 举报
回复
学习
slowgrace 2009-03-23
  • 打赏
  • 举报
回复
另外78楼和100楼可以不看了,我明白了。
slowgrace 2009-03-23
  • 打赏
  • 举报
回复
另外,考虑CDetailList改了节点名字之后通知CTree的情况,其实也说不清是放在内存块还是放到数据库里快呢?

因为当CDetailList改了DetailId为3类型为tiger的细节名字之后,CTree得到这样的消息,它就要遍历它的节点集合,找DetailId为3类型为tiger的节点,然后通知CTreeCtl改相应节点的text

如果CTree有数万个节点,这意味着它要遍历数万个Node对象或结构来找相应的节点ID。而如果CTree不保存数据,而是直接到数据库里去得到相应的节点ID的话,那是一个SQL查询的时间。
jhone99 2009-03-23
  • 打赏
  • 举报
回复
呵呵,帮忙
slowgrace 2009-03-23
  • 打赏
  • 举报
回复
[Quote=引用 116 楼 Tiger_Zhao 的回复:]
引用 103 楼 slowgrace 的回复:
为什么用数组不用集合呢?用集合的话我要定位到特定detail,只要用key就可以直接引用。用数组的话,还得找一番。是吧?
工程内定义的结构无法赋给 Variant 变量,也就无法加到集合中。解决方法:
A)在 tlb 中定义结构,就可以加到集合中。
B)用数组存放结构,将 Key-Index 对应关系加到集合中,也能快速定位。
C)用有序的数组存放结构,直接用二分法查找。
[/Quote]

我准备用二分法。因为tlb不了解,而且不知道VBA是否能支持;而key-index不好对应,因为,detailid是自动编号的,随着记录删除,会出现很多空洞。

另可否看看78楼和100楼,谢谢。
slowgrace 2009-03-23
  • 打赏
  • 举报
回复
另外,请zhao看看78楼那个帖子的63楼,谢谢。
slowgrace 2009-03-23
  • 打赏
  • 举报
回复
tlb是什么?
Tiger_Zhao 2009-03-23
  • 打赏
  • 举报
回复
[Quote=引用 103 楼 slowgrace 的回复:]
为什么用数组不用集合呢?用集合的话我要定位到特定detail,只要用key就可以直接引用。用数组的话,还得找一番。是吧?[/Quote]
工程内定义的结构无法赋给 Variant 变量,也就无法加到集合中。解决方法:
A)在 tlb 中定义结构,就可以加到集合中。
B)用数组存放结构,将 Key-Index 对应关系加到集合中,也能快速定位。
C)用有序的数组存放结构,直接用二分法查找。
slowgrace 2009-03-23
  • 打赏
  • 举报
回复
remark
冰岛男孩 2009-03-23
  • 打赏
  • 举报
回复
mark
slowgrace 2009-03-23
  • 打赏
  • 举报
回复
看看
tfpe_24_11 2009-03-23
  • 打赏
  • 举报
回复
进来学习一下
神马都能聊 2009-03-23
  • 打赏
  • 举报
回复
[Quote=引用 121 楼 slowgrace 的回复:]
另外,考虑CDetailList改了节点名字之后通知CTree的情况,其实也说不清是放在内存块还是放到数据库里快呢?
[/Quote]
数万个节点,自己写代码测试吧

数据库的应该不如内存

别人说的再多,也不如你自己手动写过之后来的真切
slowgrace 2009-03-23
  • 打赏
  • 举报
回复
mark
Wind_Runner 2009-03-22
  • 打赏
  • 举报
回复
支持一个!
funer 2009-03-22
  • 打赏
  • 举报
回复
路过
__浮夸 2009-03-22
  • 打赏
  • 举报
回复
正再学习中!!
加载更多回复(102)

7,763

社区成员

发帖
与我相关
我的任务
社区描述
VB 基础类
社区管理员
  • VB基础类社区
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧