1.在基于DELPHI的面向对象系统中,对数据库操作应如何进行静态和动态设计?
不知大家有否注意到,如果完全使用面向对象形式对数据库系统进行构造,则在使用时会产生大量的对象实例,因为“一类一表”结构所对应的应该是“一记录一对象实例”,即便使用“懒对象”,如果同时操作的记录一多,其实例数量也会相当惊人,而且用此方法又如何对检索后的数据进一步检索呢(难道非得放着SQL不用,而用手工检索吗?)
DELPHI提供的TQUERY/TTABLE等控件是基于“一对象一表”的,但我不清楚是否真的能用这种结构进行面向对象设计,还是只能把它作为一个用于检索或生成视图的工具类?所以我想问一下大家在DELPHI中是如何进行“面向对象”数据库系统设计的?(还是依然在使用面向过程设计?又是如何对系统中其它的“类”进行协作?我这次依然使用了面向过程方式,但没有找到从面向对象到面向过程的映射关系)一个简单的例子:一个组管理多个用户,一个用户只能加入一个组;一个组拥有一组资源,一个资源只属于一个组;一个组可以有多个子组,每个子组也可以有多个父组;子组的资源对父组是公开的(继承关系)。
系统要求的操作是:得到某个用户所能使用的所有资源。面向对象设计的静态结构(一类一表):
                       +-----+
                     * |     |    +--------+
     +------+ *   1 +----+ * |----| 组继承 |
     | 资源 |-------| 组 |---+    +--------+
     +------+       +----+
                       | 1
                       | *
                    +------+
                    | 用户 |
                    +------+
面向过程(大部分管理细节由动态结构定义,也不能表现出数据库结构,但实例数少得多):
    +--------+ 1 * +--------+ 1   1 +--------------+
    |用户管理|-----|活动用户|-------|用户可用资源集|
    +--------+     +--------+       +--------------+--------------------------------------------------------------------------2.我在对一张多通道板卡进行上层包装时,注意到多数情况下,DELPHI的容器类控件会把事件指针放在子类中(也就是子类中有自己独立的事件),但如果我把它提到容器中也应是可以的(也就是多个子对象共用一个容器事件,事件参数中包含子对象引址),这样对面向对象软件设计来说只是在结构中多了一个“关联类”,但对面向过程的编程来说可以方便很多。所以我想问一下,一般大家对此类包装会更倾向于哪一种形式?为什么?

解决方案 »

  1.   

    不好意思我的DEL
    学的不是很好呀
    下次我会给你一个好的答案的呀
    真的呀
      

  2.   

    to jianlei2002:
    这2个问题应该不仅仅只是DELPHI才有的呀!
      

  3.   

    是的,事实上我到目前还认为面向对象只能作为面向过程的一种'扩展',而不应是'取代',但问题是如何对它们进行合理的结合?面向对象优点是建模实现,面向过程优点是性能(由其是速度和资源利用是面向对象无法比的),我之所以提这个问题,就是因为我没法很好地解决它们两者的关系,如何才能'优势互补'?又如何在一个系统中综合运用(关键是如何在建模中实现它)?
    我现在更习惯于用UML建模,但问题在于对建模的技术还不熟练,更是很难使之与面向过程的实现相配合,我想关系数据库应该是目前应用最多,也是最直接的切入手段了吧...请大家多谈谈啊!
      

  4.   

    对于第二个问题,我觉得如果你需要对容器中的每一个对象的事件触发都需要做一些相同的工作的时候,又或者容器内对象不公开,才需要将事件提到容器一层,其他情况下没有什么区别,要是在实际编码中,我会怎么方便怎么用。对于第一个问题 换一种思维方式,你把DataSet的每一条记录都看成一个对象吧我想说一句:不能为了面向对象而去构造对象,面向对象是为了编码方便简单易读易扩展,我个人觉得它仅仅是个方法而已,不能提升到原则的高度。有些问题想的太多就钻牛角尖了。
      

  5.   

    to rustle:
    首先我很感谢你的回答.
    但对第一个问题,可能你还没明白我的意思.我是指如果我把DataSet的每条记录看成一个对象,那么就出现了一个问题:记录是没有可执行方法的!但在实际建模时(特别是用面向对象思路建模时),对象的方法已经被有意无意地用了进去(就如同'组'中必然会包含对'用户'和'资源'的管理方法.而且,如果你把这些方法从这些类中独立出来,那么实际上你是在用面向过程的方法在建模,更重要的是,你将不可能再使用标准的数据库系统建模方法,这点如果你看过UML的相关书籍应该会了解,至少我到现在还找出不其它方法).所以我就是想了解,现在大家是如何去做的?又是如何对数据库系统地行合理建模的,特别是在DELPHI中又是如何实际运用的?我也想说一点,其实我并不是为了面向对象而去构造对象,而是为了把逻辑模型映射为实现代码而不得不这样做.(但实际上我没有这样做,因为我做不到--不知道如何合理地做,所以我实际上还是在用面向过程在开发--只不过是用了面向对象的外壳而已!)
      

  6.   

    对于第一个问题,DataSet,可以继承它,也可以包装它
      

  7.   

    to rustle:
    能否给个例子?我可以先举例说明一下我的观点:
    [组]----[用户]           // 一个组管理一群用户
    "组"会有一些基本属性和方法:
    User[Index] : TUser;     // 用户列表
    UserCount : integer;     // 用户数量
    Add : TUser;             // 增加一个用户
    Delete(Index: integer);  // 删除一个用户
    Search(...) : TUser;     // 查找某个(或多个)用户当然,我们完全可以用一个单独的类来实现上面这些方法(因为现在组和用户都不能有方法),于是我就得把模型改成下面的形式:
    [组集]--[管理器]--[用户集]    // 注意:这里只有一个组集和一个用户集,对应的管理器包含了上面所有的方法(功能)
    因为组集中有未知多个组,而每个组又有未知多个用户,所以用户集的数量不可能是动态的多个(只能是一个,如果是多个,则会使得管理器变得很盲从,因为管理器不知道那个组对应哪个用户集).这就出现了一个问题:我们必须依照使用中的'组'来动态地用SQL(或别的方法)更新'用户集'的数据!----这样尽管我们还是在用面向对象外壳,但模型实际上已经是在用面向过程的方法了!(没有了面向对象建模的根本要素----功能内聚)我想问的就是:有没有第三种更好的解决方案了?
      

  8.   

    不要把简单问题复杂化想把任何东西都理的很顺,很有条理这是不可能的建模是高层次的东西,到一定的细粒度上就不起作用了,或者说不适用了在现在的这个层次上,还不如了解一些设计模式的知识来的实际你抛开这些,抛开这些设计理论,你会发现你要处理的是一个很简单的问题你现在就想你只需要实现功能,然后去构造你的代码逻辑你所需要的只是一个DataSet,和几个相关操作的Procedure
      

  9.   

    呵呵,说得没错,我现在就是这么做的,因为这个问题的确是简单的.可如果是一个复杂系统呢?难道还是这样去做吗?我可以把上面的问题再复杂些:一个组管理多个用户,一个用户只能加入一个组;一个组拥有一组资源,一个资源可以被多个组重复使用;一个组可以有多个子组,每个子组也可以有多个父组;子组的资源对父组是公开的(继承关系);资源有自己的组织形式,且不同组的同一资源与其同组内的其它资源可以有不同的组织形式;父组在使用子组的资源时,同时也继承了子组资源的组织形式;资源的组织形式由管理员维护;不同权级的管理员可以对不同级别的组资源进行维护;管理员也属于用户(特殊用户);组中的用户也由管理员来维护;不同权级的管理员可以对不同级别的组用户进行管理(包括子管理员)。上面是标准用户资源管理系统的一部分,我知道它应当可以用你所说的面向过程来实现,但要知道对于这些有复杂逻辑关系的系统来说,用面向对象会比面向过程方便得多、准确得多、清晰得多,由其是在建模上!所以我会用UML来建模,但问题就是如何把它“翻译”成面向过程的系统来实现?
      

  10.   

    还有:为什么只有 rustle一人在回答我的问题啊?!
      

  11.   

    我知道你的意思,你是说,如果员工有 10000 个,用面向对象的办法就要造 10000 个对象,系统赔不起。而如果员工个数不确定,更需要不断的用 TMember.Create AMember.Free,这么多的对象对于运行他的系统来说,是一个沉重的打击。所以,对于单纯的数据(根本没有所谓方法),可以采用对象化的数据库设计(一类一表格),但不应沿用对象的构造函数之类的方式,除非它是容器对象。这样,我们只把 DataSet 看做对象,它管理的对象都用 DataSet['姓名'] 这样的办法来处理,因为实在说不上他们有什么方法。有一种主细表的数据库设计,可以把返回字段值为结果集的结果集,这样,DataSet['曾供职公司'].Add 'IBM' 也可能出现。想像,:P 希望看到实际应用中的解释。
      

  12.   

    对了,我就是想知道如何用DataSet来建模?而不是用单个记录!也就是如何用“一对象一表”来建模?
    能给出例子吗?最好就用最上面那个简单的题目
      

  13.   

    虽然是用 DataSet,建库的依据依然是一类一表格无疑的。变化只在于,现在让一个 DataSet 例如 DstStaff 储存和管理所有属于 TStaff 类的对象,而因为 TStaff 非常简单,按前文讲的,无所谓方法,更没有事件什么的,就不再它当做对象,在具体引用其属性时,例如引用员工张三丰的资料: DstStaff.Find('Name'='张三丰')(这句语法自然有问题:),之后 iAge := DstStaff['Age']。
      

  14.   

    我觉得面象对象的设计不是用来设计物理数据库的,物理数据库要考虑的是性能
    简单的讲就是  根本不需要一类一表,  一类可以多表,  一表可以多类
    我没用过delphi, 不知道dataset是怎么回事,但我觉得,RAD的开发工具带来快捷性的同时,也失去了灵活性。
    我觉得在需要系统良好架构的时候,不要采用数据绑定技术,建议看看.net的dataset,个人觉得很好
      

  15.   

    to inshua:
    我知道你的意思了,你是说把DataSet的每个记录看成一个对象,但使用时并不去生成实体对象,而就是用DataSet自己的记录,是不是?
    但实际上你并没有回答我的问题,我问得就是:如何用你这种方法来建模?我是指建模,而不是使用!或都说,如何把前面的"标准"模型,映射为这种模型,我没有找到方法!to qiujoe:
    面向对象完全可以用来设计数据库的,而且在某些方面比ER模型更有效更直观,最主要的就是可以直接与系统相集成,只是因为面向对象建模方法更适用于面向对象数据库,而对于关系模型,则要经过结构映射后才能使用.我没用过.net,但我想它应该用DELPHI的差不多,也就是一对象一表结构(数据集/记录集).事实上我知道确实有一种模型可以很好地实现我们的要求(因为我听说过),但我找了大量的书籍资料和网站,就是找不到这种建模方法!
    我还要说明一点,就是面向对象的核心是内聚和封装,如果于应该是由此对象来完成的方法而没有用些对象来完成,那就不能算是一个真正的面向对象系统了!(当然我不认为真正的面向对象就一定好,但有一点,如果这样做,会使得复杂系统的设计变得简单得多!)
      

  16.   

    建模的时候按面向对象的方法,一类一表格。而在恢复对象,也就是调用表的时候,按对象的方法是这样的:AStaff := TStaff.Create('张三');
    而按现在的解决办法是:DataSet.Seek ( '姓名=张三' ) //大体意思这样,DataSet 就“成为”了一个真实可用的 Staff 对象,它有和 AStaff 一样的姓名、出生日期等等属性(DataSet['姓名'])。
      

  17.   

    5555555,我也正在看,好像多懂了些,周六周日又把DELPHI高手突破翻了一遍
      

  18.   

    员工类有好多属性,其中有一个属性就是组(Group)组类是一个员工类数组(类似于TStrings),外加了一些添加删除等方法,添加一个员工时,创建一个员工,并把Group设置为当前组至于资源,我不了解是什么
    查询是查询类,查询返回一个视图,或记录集什么的,与员工类并无任何关系。点击某条记录时,从数据库主键创建员工对象,显示员工对象信息
    个人之浅见,我是这样想的,并在尽量实践,不知各路英雄有何看法?
      

  19.   

    作为面向对象的设计思路更多的应应用与功能逻辑,而数据库的操作则完全可以交给SQL完成。
      

  20.   

    先说一声不好意思,前二天一直没空,所以回来迟了.to inshua:
    可能我还是没能完全了解你的意思,所以我对你的方法作两种分析:1.你是否是"模拟"了一个"管理器类"?也就是由它来管理具体"记录对象"建立或销毁等行为,也就是依然生成一个对象,只是在真正使用时才生成它(前提是类的所有参数可从数据库或已知环境中得到),但这解决的只是一个动态分配问题,而此问题实际上完全可以用"懒对象"来解决(也就是用一个"代理类"来动态维护"具体类"的生命期).
    它所存在的问题是: 如果我同时操作的记录量很多时,此没依然很浪费(没有解决我的问题)2.还是你只是用一个"代理对象"来模拟对所有的"记录对象"的操作虚拟操作(实际上并没有记录对象),但如果这样,我不是无没在这些"对象"中建立与其它对象之间的关联了吗?(特别是动态的关联),因为我不能在这些"对象"中保存非数据库中存在的数据(如指针等),更不可能触发一个事件给别人了!哦,对了,我先声明一下,你和rustle我一定会给分的!谢谢,请继续...
      

  21.   

    看了各位大哥精彩的发言,我觉得受益非浅,其实在学习c++和java时,我发现他们很容易实现楼主所提出的要求,当然我当时只是做了一些例子程序,但如楼主所说,当我带着这些思想学习delphi或其他高性能的RAD时,我却发现这些似乎行不同,到最后仍然只能成天给那些控件打交道,陷入只见树木,不见森林的困境中,不过有一次我看了一下delphi的vcl类图,突然让我想起了java的类库,两者是多么的相似,因此我坚信面向对象程度这么高的op肯定能够
    实现oop思想,我经常在java版晃,发现里面谈论java如何实现oop和UML的经典帖子很多,相信能够对楼主有很多启发,另外在程序员杂志去年的合定本中有一篇J2EE与UML的实战文章,非常精彩,内容涵盖分析,建模,设计,实现等阶段,讲授的很详实,很具体,如果能够与delphi有所参照,相信定会对楼主问题的解决有所帮助。另外:楼主所言
    1。"不知大家有否注意到,如果完全使用面向对象形式对数据库系统进行构造,则在使用时会产生大量的对象实例,因为“一类一表”结构所对应的应该是“一记录一对象实例”,即便使用“懒对象”,如果同时操作的记录一多,其实例数量也会相当惊人,而且用此方法又如何对检索后的数据进一步检索呢(难道非得放着SQL不用,而用手工检索吗?)"实例对象确实很多,但真的很浪费资源吗,我在学习c++时有些参考书说,类的方法对所有对象来说是共享统一代码区域(方法表 Method Table),实际上程序只是存放实例的属性值和其地址,当我们调用某一对象的方法时实际上仅仅是传了一个this指针给该方法,以指示其对某一确定对象进行操作,如果我们参照delphi,这个类最好的父类不正是DataSet吗?他一般是表的在程序中的影射,他的方法不正好对应Method Table,记录的游标不正好对应各个对象地址,至于记录的字段值当然就是对应对象属性值了。比如在java的很多用来代表某个实体的java bean都是继承自RecordSet的,以上拙见还请指教,
      

  22.   

    这我到真得没注关心过,对象的方法是共享的(以前一直认为只有类方法是共享的),谢谢你的指正(尽管我现在还不清楚是否真得是这样).不过我也要指出,从Delphi的源码中看,似乎DataSet并没对每个记录元建立一个对象,而是使用了一个缓冲区,如果使用对象果真那么"节约",他们不会不用它吧?使用对象会有一系列浪费,包括属性,方法等(不要忘记还有父类和祖先类的东西也要包括在里面),再加上对对象引指的查找所花时间,对大规模操作我不认为这是合理的方法.
    还有一个关系,就是一记录一对象后,如果你要从中查找一个记录,那你就不得不使用完全手工的查找方法,但如果你使用TQuery或ADO,那你就可以使用SQL了.我现在头痛的是"组的继承关系",因为组可以有子组(这一迭代是无限的),所以我如何才能用最合理的方法得到一个组所包含的所有资源(也就是组和其所有子组的资源集合),如果我不使用对象型记录,我如何去实现这一关系呢?(我现在是用动态关联的方法来实现,但这不是面向对象的方法)
      

  23.   

    其实我觉得楼主钻的很深啊,从UML到vcl原码,本人实在佩服。另外我说的“类的方法对所有对象来说是共享统一代码区域(方法表 Method Table)”完全是基于C++的,至于delphi我还没有深入到代码级,但楼主所言“对对象引指的查找所花时间,对大规模操作我不认为这是合理的方法.”,我觉得有些不解,难道sql语句查询就不花时间?即便是由数据库承担查询任务,但程序与之通信又不费资源?另外我在发言中一直强调Java与UMl就是想跟楼主说, java能够这样做(他可是完全面向对象的),怎么就不怕你所说的
    “使用对象会有一系列浪费”,怎么还是那样"火",其实我真正目的是希望楼主能从JAVA中有所借鉴和启发。
      

  24.   

    http://www.shecn.com/zippdf/LibrarySystem.zip这是一个基于java的图书馆管理系统的UML实例,虽然是英文,但图例很多
    而且我相信楼主的E文不算差吧,我一直觉得在java的UML建模过程中
    同样也会遇到如楼主所说的问题,另外你的核心问题是不是如何建立数据库
    表记录与UML建模中的对象的合理高效的影射?我也在看,希望共同学习!
      

  25.   

    你说得没错,因为我没有正真去测试过结果如何(因为我还不感去试,谁都知道错了会有什么后果),不过我个人认为SQL的优点在于对查询的全面优化和集成,毕竟人家有一整套的优化手段.而我所说的"对大规模操作我不认为这是合理的方法"中,"对对象引址的查找所花时间"可能只是其中的一部分,真正多的时间可能是查找算法的性能上(可能比不上SQL),但经你一说我到是有些"开窍"了:SQL中的面向全局的综合查找可能并不比我具有强针对性的局部查找来得快.我正在思考中...我不清楚java在实现上是否真得和它标准的模式完全一样,但有一点,我知道那种非一类一表的设计模式一定存在,因为我看到过有关的介绍,但只是介绍,在我找的所有资料和书籍中都没有真正解释它!
    还有,我看得是<UML和模式应用>(Craig Larman著),此书就是基于java平台的,虽然我没用过java,但感觉java好象并没有封装类似于DataSet的类,因为书中的模型给出了完整的数据库建模(包抱事务的实现过程),所我我认为用java和用delphi必然有不同,应该是平台设计者有不同中的思维模式,但我不清楚delphi的设计者是希望给我们一种什么样的数据库开发模式?从我个人角度看,delphi的DataSet等VCL己经很好地封装了对数据库开发框架(包括事务),所以实际上我是在寻找一种符合delphi思想的数据库开始模式(而不是java).它是怎样的?你给我的资我正在看,先谢谢了!
      

  26.   

    http://java.sun.com/j2se/1.4.2/docs/api/java/sql/ResultSet.html这个就是类似于DataSet的接口(不好意思今天我写错了,不是类),我曾经用
    过,你看看它的用法和属性几乎和adoquery一样
      

  27.   

    看来我真得有些糊涂了,我究竟要如何去建模?
    因为现在看来,无论是delphi还是java或是.net开发框架,很多时候我们使用的并不是类,而是它们的框架(就象VCL).我开始怀疑,我们是不是根不就不应该使用"面向对象"来建模,而是应该用"面向框架"建模(当然我也知道它是基于面向对象的)?如果是就样,那前面的所有的矛盾就都能解释了,下一步是就学习如何进行面向框架的建模了...plq多谢了,此贴拖得时间太长了,这两天内我会把它结了.因为我E文不好,所以你资料我看得比较慢,如果有什么好的想法,请和我多多联系:[email protected].
      

  28.   

    哦,对了,看来你学得很多吗,是不是从java转过来的?
      

  29.   

    偶觉得是这样的。
    记录是类,
    表是类的集合,
    应该是这样。
    但是 一般做数据库也没有必要
    弄的太清楚了。
    呵呵,
    但OOP做数据库 必须面队的问题是OR MAPPING
    偶认为。
    偶现在还没有什么好办法。
      

  30.   

    其实我也觉得是这样,象我们这种普通程序员只能跟着人家的Framework走,
    而且他们封装的也不错,至少从表象来看他们OOP(当然实现我就不怎么了解了),
    说真的关于delphiUML建模的例子好象很少。不过据说在D7里有一个附带的UML建模工具,不懂是不是真的,如果是这样的话
    肯定有例子,我找找看!
      

  31.   

    我就是因为D7有ModelMaker所以才用它的,不过在使用中感觉它对UML规范作了自己的改动,所以开始有些不太适应,现在还好,但功能上不象其它专业工具那么强,不适合建业务逻辑模型,优点是对Delphi的支持比较好,建物理模型不错.
      

  32.   

    它的例子太少了...(ModelMaker好象是bland买来的)
      

  33.   

    >>完全使用面向对象形式对数据库系统进行构造
    有必要吗?
    现有数据库系统多是关系数据库,如果“完全使用面向对象形式对数据库系统进行构造”,不就相当于做一个面向对象的数据库系统了?
      

  34.   

    建模的目的是在于描述和理解复杂的系统
    所有模型直接变为code 是不现实的
    同意一类多表或一表多类
      

  35.   

    其实这个topic根本的问题有两个:o/r mapping和object persistence。
    国外早有成熟的理论及方案。理论看这里:
    1.Encapsulating Database Access 
    http://www.agiledata.org/essays/implementationStrategies.html2.The Fundamentals of Mapping Objects to Relational Databases
    http://www.agiledata.org/essays/mappingObjects.html3.The Design of a Robust Persistence Layer for Relational Databases
    http://objects.nease.net/persistenceLayer_ch.pdf(中文版)delphi下成熟的方案首推由BoldSoft开发,后被Borland收购的bold for delphi。
    其它的还有InstantObject,ObjectSight, tiOPF等。大家还是站在巨人的肩上吧。