reallike(认真学习Cpp用Cpp考虑delphi)和ZyxIp(绝望中...)昨天看到你们的讨论,小弟受益无穷。从昨天一直想到现在。想我原来我的做法我的想法。对于面向对象一直不得要领。还想请教:    我从半年前开始用DELPHI写程序,在此以前一直用VB做东东,确切的说VB并不是完全面向对象的语言(这样说没错吧?),或者是我本人没有这种思想吧。用现在的眼光来看,原来我应该是一直是面向过程编程。    我以前做过一个点歌系统(VB写的),看代码几乎没有面向对象的概念在里面。所以,我想用DELPHI重写一遍,用面向对象的方法去写。练练手也好,刚好我又比较熟悉这些业务。其实点歌系统没有什么东西,所以我把定义了以下几个类:   T点歌钮=class(Tbutton)  //多加些属性
   T歌曲=class             //总的歌曲
   T分类歌曲=class(T歌曲)    //分类的歌曲
   T单曲=class(T分类歌曲)     //对单一歌曲的描述
   
   基本就是这些对象了,不知道这样分对不对?然后就是一些控制性的过程及函数。这些过程和函数需不需要也归类成一个对象?还是怎么样?还是把它们分散到T单曲或T分类歌曲的类中?
   
   对于面向对象,我真是一知半解,请两位看一下我这样做好不好?怎么样做才算是符合面向对象?还有就是,如果我定义了这些类之后,我怎么样去在实际的开发中便用它们?比如我现在要把歌曲数据从数据库里面取出来然后显示到LISTVIEW里?怎么样去通过定义好的对象做到面向对象编程?   呵呵,不好意思,可能提的问题太多了,我当然希望两位能够帮忙回答这些问题,但是如果你们没空也没关系,我也一样感谢。如果分不够可以再开贴给分。我说用点歌系统做例子只是我比较熟悉这个业务。如果有其它例子也可以的。   总之谢谢你们。   :)

解决方案 »

  1.   

    bestluo(要学) ,Drate(小虫) 面向过程也是一样的吧。也可以做些公用的模块重用吧我知道刻意去追求某种编码规则反而会得不偿失。但是我只是想更深刻的去实践面向对象的编程方法。如标题一样。我还问了好多问题呢,各位怎么没见回答哦?
      

  2.   

    没有必要刻意追求OO,有时候不用OO效率更高,比如游戏编程...总之:只要能够达到自己的目的,谁简单就用谁!不择手段!
      

  3.   

    连续三个帖子,讨论关于面向对象的东西!说句实在话,面向对象做为一种方法论,内容虽然很多,但抽其精华,也可以很简单的总结出来,但总结出的语句中包含的更深一层的思想却非常广博。我无能进行这种总结,更不敢对面向对象的全部内容保证精通,只能凭借先前所经历过的开发过程和自己对这个理论的了解程度来说说如何在开发中使用面向对象理论!首先任何一个业务过程都可以在我们脑海里顺利的模拟下来,即使这种业务过程很复杂!但即使在复杂的业务过程都可以分解成相对复杂性较小的过程。或者更确切的说任何业务过程都是按环节来循序进行的,虽然业务中可能存在各种同步或异步的流程,但独自考虑单个流程,都可以划分为各自联系的环节。而这些环节往往就是我们在业务流程中相对具体的业务动作。同时针对每个业务动作,都会涉及到一些具体数据。因此,至此,我们可以清楚的看到整个业务流程并非模糊不清的。无非就是业务流程,业务动作和业务数据三者的组合。对于每个业务动作,发出对象均涉及业务流程中参与实际业务的相关部门或人员。因此,站在面向对象的角度去考虑这个业务过程,我们完全可以用类来实现对发出具体业务动作的相关部门或人员的封装。这样,通过若干个类就可以完整的对整个业务流程所以参与部门或人员的包装。这是其一!其二,有了类的框架,没有标识类的状态的数据和对类状态进行更改的对应方法,这样的类结构是能是徒有虚名,所以接下来,就是在对对象封装的基础上进一步将业务中所有动作进行划分的工作。其实在进行业务参与对象封装的过程中,我们如果不对动作进行划分是很难抽象出与实际业务参与对象相对应的类的。所以这里重要的一点是如何将前期所做的划分更细化,更合理化。如何做到这些我想没有必要细讲,也很难细讲,因为不同的业务流程,千差万别,很难用一种统一的原则进行概述。所以要具体情况具体对待。但到了这里需要很明白的一点就是,我们软件的类结构是完全依赖实际业务流程中的部门关系或人员关系的,所以考虑到业务动作的抽象对应与开发中的结构设计就是将业务动作用方法的形式附着于以抽象出的类中。接下来就是考虑业务动作中数据的操作问题了!最后,说到数据的操作,任何业务动作都不可能不涉及数据的,但如何对这些数据进行抽象呢?这需要从两个方面进行考虑,数据分两种,一种是和业务完全结合的数据,这类数据和业务参与对象自身没有多大关系,因此这类数据可以做为入参传递给方法;对于另外一种数据则可以作为描述类状态的数据成员附着与类上。总的来说是这样,但数据的操作必然涉及数据库表的结构设计。个人认为数据库表的结构和类结构两个设计并无多大关系,但一般情况下我会以类结构设计参考数据库表的结构设计,但这也仅仅是种参考!至此,基本类结构设计完成。当然这样的设计最明确体现的是简单的MIS系统,对于多层设计,需要在此基础上进行更细化的结构调整。由于没有多少实际经历,所以暂不涉及。面向过程只是一种指导开发的思考方式。但个人认为一个软件的设计很难用纯粹的OO理论来进行规划。一般的软件开发过程都是大比例的面向对象和小比例的面向过程的结合。至于软件的复用度,我想如果面向对象的思想能比较好的运用于软件开发的规划阶段,软件的复用度会提高,同时软件的重构过程也不会变的混乱,最后导致因为功能的更改而彻底毁掉先前的开发成果!
      

  4.   

    连续三个帖子,讨论关于面向对象的东西!说句实在话,面向对象做为一种方法论,内容虽然很多,但抽其精华,也可以很简单的总结出来,但总结出的语句中包含的更深一层的思想却非常广博。我无能进行这种总结,更不敢对面向对象的全部内容保证精通,只能凭借先前所经历过的开发过程和自己对这个理论的了解程度来说说如何在开发中使用面向对象理论!首先任何一个业务过程都可以在我们脑海里顺利的模拟下来,即使这种业务过程很复杂!但即使在复杂的业务过程都可以分解成相对复杂性较小的过程。或者更确切的说任何业务过程都是按环节来循序进行的,虽然业务中可能存在各种同步或异步的流程,但独自考虑单个流程,都可以划分为各自联系的环节。而这些环节往往就是我们在业务流程中相对具体的业务动作。同时针对每个业务动作,都会涉及到一些具体数据。因此,至此,我们可以清楚的看到整个业务流程并非模糊不清的。无非就是业务流程,业务动作和业务数据三者的组合。对于每个业务动作,发出对象均涉及业务流程中参与实际业务的相关部门或人员。因此,站在面向对象的角度去考虑这个业务过程,我们完全可以用类来实现对发出具体业务动作的相关部门或人员的封装。这样,通过若干个类就可以完整的对整个业务流程所以参与部门或人员的包装。这是其一!其二,有了类的框架,没有标识类的状态的数据和对类状态进行更改的对应方法,这样的类结构是能是徒有虚名,所以接下来,就是在对对象封装的基础上进一步将业务中所有动作进行划分的工作。其实在进行业务参与对象封装的过程中,我们如果不对动作进行划分是很难抽象出与实际业务参与对象相对应的类的。所以这里重要的一点是如何将前期所做的划分更细化,更合理化。如何做到这些我想没有必要细讲,也很难细讲,因为不同的业务流程,千差万别,很难用一种统一的原则进行概述。所以要具体情况具体对待。但到了这里需要很明白的一点就是,我们软件的类结构是完全依赖实际业务流程中的部门关系或人员关系的,所以考虑到业务动作的抽象对应与开发中的结构设计就是将业务动作用方法的形式附着于以抽象出的类中。接下来就是考虑业务动作中数据的操作问题了!最后,说到数据的操作,任何业务动作都不可能不涉及数据的,但如何对这些数据进行抽象呢?这需要从两个方面进行考虑,数据分两种,一种是和业务完全结合的数据,这类数据和业务参与对象自身没有多大关系,因此这类数据可以做为入参传递给方法;对于另外一种数据则可以作为描述类状态的数据成员附着与类上。总的来说是这样,但数据的操作必然涉及数据库表的结构设计。个人认为数据库表的结构和类结构两个设计并无多大关系,但一般情况下我会以类结构设计参考数据库表的结构设计,但这也仅仅是种参考!至此,基本类结构设计完成。当然这样的设计最明确体现的是简单的MIS系统,对于多层设计,需要在此基础上进行更细化的结构调整。由于没有多少实际经历,所以暂不涉及。面向过程只是一种指导开发的思考方式。但个人认为一个软件的设计很难用纯粹的OO理论来进行规划。一般的软件开发过程都是大比例的面向对象和小比例的面向过程的结合。至于软件的复用度,我想如果面向对象的思想能比较好的运用于软件开发的规划阶段,软件的复用度会提高,同时软件的重构过程也不会变的混乱,最后导致因为功能的更改而彻底毁掉先前的开发成果!
      

  5.   

    举个简单的例子,比如工厂A有三个部门,分别是DA,DB,DC,对应其中的部门DA,主要负责工厂人员的考勤登记等业务。所以现在考虑到考勤登记这个业务动作,首先明白一点,登记的这个动作是由部门DA发出的,接下来就需要考虑这个登记的动作都会涉及什么样的数据,虽然这些数据和DA部门本身没有多大的关系。这里登记的数据可能包括登记日期时间RollTime,被登记人员相关信息,这里仅用人员编码StaffID表示,或者还有其他一些相关信息,我们暂且不考虑。这样,至此,我们就完全可以在我们的类结构设计阶段进行入定类定义:type
      TDepartmentA=class(TSomeAbstractClass)
        public
          function RollStaffInfo(ARollTime:TDateTime;AStaffID:Word):Boolean;
      end;
    这样,我们在单独的单元中对这个部门以及相关动作进行了代码实现后,接下来就可以通过定义对象来模拟实际业务部门的实际业务动作!当然,一个软件的类结构中最后可的非常层次化,充分利用多态的OO特性,这样可以使软件在内部结构上复用度和可扩展性更高。
      

  6.   

    对象的概念是很抽象的,因为抽象,所以才可以用于各行各业的各种情况!同时,尽量将类结构做的层次化一些,具备一些抽象基类的基础上,进行扩展,这样做的好处是可以对功能进行细化和便于将来扩展!当然,复用程度从另外一个角度来说,也是可以提高的。Delphi提供的各种语言功能,可以确保类结构设计的灵活性,覆盖(override)可以提高可扩展性,重载(overload)则可以使同一个对象的某一个动作同时处理不同类型的数据,而reintroduce则可以完全丢弃父类的定义而重新定义等等。这些方法都可以使我们在利用面向对象进行程序类结构设计的时候做到更加灵活,就看你是否用它了!
      

  7.   

    fs 你叫我来 我以为又遇到什么难题了呵呵帖子申请faq~~~~!!
      

  8.   

    楼顶的土豆兄。要真正知道面向对象,得有两点你需要学习。一、抓住要害,抓住重点,不要局限于一点,而是从大的方面,总体来考虑。二、目的要明确,不要被细节问题给转移视线,这样会因小失大。因为我们要做到“面向”对象,首先你要找到你的对象,然后面对他,针对他来思考。而你的:   T点歌钮=class(Tbutton)  //多加些属性
       T歌曲=class             //总的歌曲
       T分类歌曲=class(T歌曲)    //分类的歌曲
       T单曲=class(T分类歌曲)     //对单一歌曲的描述我看不出有一点点歌的东西。请你再写写好吗?
      

  9.   

    哎呀,是呀。多结合些实例呀。我是越看越糊涂了。
    老实说,通过这几天看帖子,让我感觉我的delphi简直就是白学了。我就像是一直在用pascal编程序。面向对象我从来没有特意的使用过,差距太大了!
    希望高手们能多结合些实例谈理论,我基础太差,理解不了呀。
    我再举个例子,你们看怎么用oo设计类:一个简单的股票收支统计软件,
    表operation记录了每次交易动作,包括日期,股票代码,操作,数量,价格
    表stock记录了所持股票信息,包括股票代码,持股数,均价
    表stockname记录了股票名称,包括股票代码,股票名称,主要作为上面两表的从表。现在有以下操作:
    用户可以向operation添加记录
    用户添加记录时,经过计算,自动向stock添加或删除记录
    用户可以查看stock记录如果让我做,我会直接在datamodule上添加几个query,根本想不起来设计什么class,请大家指教,如果用oo的思想,应该如何设计class呢?请说得具体些,我真的好菜,谢谢了!
      

  10.   

    我对你的话根本就没有说,当然不具体。我只是针对楼顶的对项目的分析的一些不恰当做法提出我的一些看法。面向对象,首先就是考虑面向的“对象”是什么,自己面向的对象都不明确,怎么在一个项目里面有针对性地作为?重点不明确,没有核心,会造成一种混乱。把对象树立好了,再谈面向。如果对象树立不正确,再谈面向同样是空谈。围绕对象来操作,才是面向对象的一个本质。之后才是使用软件工程之类的技巧和经验。对于这个问题,我打个比方,打个大一点的比方。可能FS从来没有想,但是我想了。我们的人生,我们的人生所要面向的对象,也就是我们的人生目标你明确了没有?人生目标明确再说逐步实施的细节,里面可能有坎坷,可能有幸福。但是都是细节都是为我们的目标而服务的。但是大前提,就是找到对象。再打一个比方,最近FS失恋,我就拿这个来打比方。FS你是否考虑你的对象——嘿嘿,还真是对象——她到底是什么形象?什么素质?你有没有目标,也就是对象?你是否真地树立了合理的对象?假如你树立好了,中间任何不择手段的方法,仅仅是手段。:〉好,咱们回到他的点歌系统,既然是点歌系统,那就要从点歌入手。尽管看上去点歌确实简单,好像不值得做似的。但是它是核心。它才是最重要的。因为要做的是“点”歌。而不是“管”歌,不是歌库,更不是点歌按钮……如果从界面,从歌曲入手,那就出现实质性的失误,他们仅仅是细节,尽管从技术含量来说好像比点歌来的困难,但是要分清主次。好了,明确目标我再和FS讨论具体的实现。
      

  11.   

    一般说来,无论是面向对象还是面向过程,在步入程序编写之前,我们首先要解决数据流动的问题,也就是怎样从现实中得到数据,这牵扯到你要用什么数据结构存储这些数据的问题,实际上,你在考虑用什么数据结构存储这些数据时,在一些小的项目或者数据处理不复杂的项目中,你的算法也就出来了。做完这些,你才能考虑怎样把处理完的数据导给用户,或者说,你开放哪些接口给你的那些界面,说实话你可以把这些接口放到一个开放的思维中考虑,比如,你把这些接口封装成组件。
        我上面的这些话,实际上是在重复一句话:编程等于数据结构加算法。
        具体你用什么样的思想来处理上面的过程,是你的事。好,按照楼上兄弟们的说法,我们看看怎样用面向对象的思维完成这个过程。
        就拿楼主的这个例子来说吧。
        一个简单的股票收支统计软件,
        表operation记录了每次交易动作,包括日期,股票代码,操作,数量,价格
        表stock记录了所持股票信息,包括股票代码,持股数,均价
        表stockname记录了股票名称,包括股票代码,股票名称,主要作为上面两表的从表。   现在有以下操作:
       用户可以向operation添加记录
       用户添加记录时,经过计算,自动向stock添加或删除记录
       用户可以查看stock记录   如果让我做,我会直接在datamodule上添加几个query,根本想不起来设计什么class,请大家指教,如果用oo的思想,应该如何设计class呢?请说得具体些,我真的好菜,谢谢了!
       看看这三个表,我要说其中Stock表少了一个关键的column:用户名,或者说用户代码。这样这三个表才能真正有了联系。
        ok,看看你的动作,从你的动作中我们看到了几个名词:用户、operation表、记录、stock表。为了说明简单,我觉得在这个程序中,我们用一个类CMydatebase处理和数据库打交道,也就是说operation、stock、stockname这三个东西除了在你的CMydatebase类中能出现(一般情况下是出现在私有的成员函数和成员数据中),其他地方,这三个表是不可能出现的。好了,现在没办法,必须有一个用户类了。现在我们要有一个清醒的认识,如果你是股票买卖的用户,你在用我们这个软件时,作为系统分析员的你,你是否觉得用户需要知道有我们的软件中有一个数据库,数据库中有三个表:operation、stock、stockname。呵呵,当然不需要,用户只需要知道再敲用户代码和密码后,进入我的交易界面,能进行交易,当然只要输交易的股票代码、数量、价格、操作(买或卖),就行了。同样的,你的用户类和用户也只要知道这些事,他不需要知道有个数据库那些东东,不过作为用户类,他要和我们的CMydatBase打交道,至于你把CMydateBase作为用户类的数据成员还是作为某个成员函数的参数。或者,把用户类作为CMydateBase的数据成员或某个成员函数的参数。这些是你张开手脚的地方了。
        呵呵,作为面向对象的架构师来说,在对系统分析时,首先要从用户角度看问题,哪些东西是那些东西所要知道,那些东西是那些东西不要知道的,这些是划分类的重要依据。这也是面向对象思想的重要的一个发面:你的对象的世界就是一个用户所看到的世界的一个翻版,开句玩笑说,你的类图,用户是看得懂的。
        当然,面向对象的重用也是一个特点,具体怎样用,我觉得在给系统划分类时,你自然用的上。
      

  12.   

    一般说来,无论是面向对象还是面向过程,在步入程序编写之前,我们首先要解决数据流动的问题,也就是怎样从现实中得到数据,这牵扯到你要用什么数据结构存储这些数据的问题,实际上,你在考虑用什么数据结构存储这些数据时,在一些小的项目或者数据处理不复杂的项目中,你的算法也就出来了。做完这些,你才能考虑怎样把处理完的数据导给用户,或者说,你开放哪些接口给你的那些界面,说实话你可以把这些接口放到一个开放的思维中考虑,比如,你把这些接口封装成组件。
        我上面的这些话,实际上是在重复一句话:编程等于数据结构加算法。
        具体你用什么样的思想来处理上面的过程,是你的事。好,按照楼上兄弟们的说法,我们看看怎样用面向对象的思维完成这个过程。
        就拿楼主的这个例子来说吧。
        一个简单的股票收支统计软件,
        表operation记录了每次交易动作,包括日期,股票代码,操作,数量,价格
        表stock记录了所持股票信息,包括股票代码,持股数,均价
        表stockname记录了股票名称,包括股票代码,股票名称,主要作为上面两表的从表。   现在有以下操作:
       用户可以向operation添加记录
       用户添加记录时,经过计算,自动向stock添加或删除记录
       用户可以查看stock记录   看看这三个表,我要说其中Stock表少了一个关键的column:用户名,或者说用户代码。这样这三个表才能真正有了联系。
        ok,看看你的动作,从你的动作中我们看到了几个名词:用户、operation表、记录、stock表。为了说明简单,我觉得在这个程序中,我们用一个类CMydatebase处理和数据库打交道,也就是说operation、stock、stockname这三个东西除了在你的CMydatebase类中能出现(一般情况下是出现在私有的成员函数和成员数据中),其他地方,这三个表是不可能出现的。好了,现在没办法,必须有一个用户类了。现在我们要有一个清醒的认识,如果你是股票买卖的用户,你在用我们这个软件时,作为系统分析员的你,你是否觉得用户需要知道在我们的软件中有一个数据库,数据库中有三个表:operation、stock、stockname。呵呵,当然不需要,用户只需要知道再敲用户代码和密码后,进入我的交易界面,能进行交易,当然只要输交易的股票代码、数量、价格、操作(买或卖),就行了。同样的,你的用户类和用户也一样只要知道这些事,他不需要知道有个数据库那些东东,不过作为用户类,他要和我们的CMydatBase打交道,至于你把CMydateBase作为用户类的数据成员还是作为某个成员函数的参数。或者,把用户类作为CMydateBase的数据成员或某个成员函数的参数。这些是你张开手脚的地方了。
        呵呵,作为面向对象的架构师来说,在对系统分析时,首先要从用户角度看问题,哪些东西是那些东西所要知道,那些东西是那些东西不要知道的,这些是划分类的重要依据。这也是面向对象思想的重要的一个发面:你的对象的世界就是一个用户所看到的世界的一个翻版,开句玩笑说,你的类图,用户是看得懂的。
        当然,面向对象的重用也是一个特点,具体怎样用,我觉得在给系统划分类时,你自然用的上。
      

  13.   

    针对楼主所说的,“把歌曲数据从数据库里面取出来然后显示到LISTVIEW里”,这个是Java的强项了。在Delphi中,可以参照Java的设计思想和实现方式进行设计。
    1。首先,我认为直接把数据库里面的数据转换到LISTVIEW,就是一种函数映射,感觉是面向过程的实现方式。这里,最贴切得面向对象实现方式就是MVC.歌曲数据是最本质的东西,也就是MVC结构里面的M(模型),而ListView很显然是V(视图)。除此之外,我认为数据库也是视图,是模型数据M在磁盘上的视图V。两个视图有着相同的模型,但两个视图却有不同的结构。数据库是关系结构,而LISTVIEW是层次结构。这样就有一个问题:M采用什么结构?我认为采用和LISTVIEW同构的层次结构是比较合理的,这样子更符合面向对象的思想。但很可惜,现在面向对象的数据库还不成熟,因此从M向数据库中的映射就必须设法实现异构间的转换。我真诚期待将来,会有savetodatabase,loadfromdatabase等等类方法,那样子就不需要现在这么多复杂的异构转换工作了。
    2。MVC主要的特点就是可以保证M-V之间的一致性,我们可以采用observer模式保证这种一致性。Delphi的Framework中,很多地方都是MVC的思想,却没有提供对MVC的库支持,需要另行设计。另外,程序也许并不需要一次性读入数据库的所有字段,某些字段如歌曲wav数据等,是很庞大的字段,却不是key字段。这样,我们可以proxy模式来实现从内存到磁盘的一一映射,来提高程序的性能。
    3。我认为点歌系统,用上面的方式实现,是不聪明的。因为该系统规模尚小,不需要频繁升级,也没有很大的复用价值。楼主所说的那种VB的“面向过程”的实现方式,我认为反而是最适合不过的了。当然用Delphi的“面向过程”会更好了。
    4。即便是面向对象的方式,我认为:
        T歌曲=class             //总的歌曲
        T分类歌曲=class(T歌曲)    //分类的歌曲
        T单曲=class(T分类歌曲)     //对单一歌曲的描述
       这样的分类也是不恰当的。我奉劝楼主牢记,除非是必须的模式,否则不要使用继承,而且,如果不是Framework,最多最多派生一层子类。
       我认为最主要两个基类是:
       T歌曲和T点歌器,前者是被动类,后者是主动类。
       T歌曲应该封装歌曲应具备的play,getName,setSinger这样的过程
       T点歌器应该封装choose,execute等方法。
       即便仅仅两个类,具体的设计很复杂,而且没有必要。
    5。在平时学习和工作中,我最感兴趣的是面向对象,用的最多的却是面向过程。面向对象,做得好的语言是java,而不是Delphi.应用程序设计,做的好的是Delphi,而不是Java.我先声明对语言没有任何偏见,更不希望跟贴中出现任何有关讨论语言好与坏的贴子。但如果单纯想学习面向对象思想,可以考虑以Java作为辅助工具。原因是:1。目前面向对象的好文章好书籍,大多数是C++/Java实现。2。Java的Framework中,更好的支持了面向对象,使用Java的Framework,实际上就是面向对象的一部分。
      

  14.   

    这算是oo的bug吗?
    假设一个class有一个private方法,无论它是静态的还是动态的,如果我创建一个子类,将同名的方法声明在public中,由于我并没有对它重载,所以delphi会自动调用父类中的同名方法。也就是说,通过我创建的子类,可以访问到父类中的private方法。这样岂不是就起不到保护的目的了吗?这算不算是private的bug呢?
      

  15.   

    这算什么bug啊,你既然用了它的子类,当然可以访问private。如果你的儿子都不能拿你们家的东西,那就不算儿子了……private是防止其他类来访问。当然不能阻止你的子类继承这个。
      

  16.   

    这算什么bug啊,你既然用了它的子类,当然可以访问private。如果你的儿子都不能拿你们家的东西,那就不算儿子了……private是防止其他类来访问。当然不能阻止你的子类继承这个。
      

  17.   

    首先说一点,我说的仅仅是参考,我说的不能拿去马上就用,我只是说有关楼顶的点歌系统,我的思路还有大致的代码。请大家畅所欲言。不过要是自己的想法,或者自己总结别人的。总归最好还是自己的。而且我能说出来概念,说明我的水平仅仅是中档。
    好,反正就面向对象这个方法论来讲。前提是找到目标对象。假设我们找到了合适的对象。申旻在他的书里面有这么一句话,设计的关键就是“抽象”。首先要明白抽象到底为我们做了什么。抽象有如下的解释:1、将复杂物体的一个或几个特性抽出去而只注意其他特性的行动或过程(如头脑只思考树本身的形状或只考虑树叶的颜色,不受它们的大小和形状的限制)。
    2、将几个有区别的物体的共同性质或特性形象地抽取出来或孤立地进行考虑的行动或过程抽象对于将东西分成属及种是必需的。是的,有第一点解释就够了,够让我们知道抽象的重要性了。我们要做点歌系统,其他的都别管,我们就说点歌。嗯,点歌,我以前没有做过,好吧,现在就来做做这个东西。我在我的白板上写下了两个大字——点歌。点,是通俗的说法,也就是说作出一种选择。当东西多了的时候,选择还是比较困难的。但是我们选择之后要做什么呢?播放,对,实质其实还是播放歌曲。所以我在点歌上面写下了,播放。哦,好了,我们所有的工作其实是为了播放而作的。所以,我要建立一个抽象的基类,我在点歌左边写下了TChooseSongs哦,他的第一个过程一定是个public的,因为它就是最重要的播放。Procedure PlaySongs(FileName: String);Boolean; virtual; abstract;为什么是虚函数后面会解释。哦,文件名应该是被保护的,所以FFileName应该在private里面所以简单的基类建立了。如果有其他的功能扩充再说。TChooseSongs = class
    private 
      FFileName: string;
    public
      Procedure PlaySongs(FileName: String);Boolean; virtual; abstract;
    end;哦?如何访问FFileName呢?嗯,对了,我们需要一个方法,一个函数来传递FFileName。OK,我们就用Template Method来建立这个类,去得到FFileName。还需要一个过程来得到FFileName,不能直接来用。TChooseSongs = class
    private
      FFileName: string;
    protected
      procedure DoLoadFile(FileName: string); Virtual; abstract;
    private
      Procedure LoadFile(FileName: string);
      Procedure GetFileName; string;
      Procedure PlaySongs(FileName: String);Boolean; virtual; abstract;
    end;template mothed就是如此了,很简单的LoadFile的代码实现。Procedure TChooseSongsLoadFile(FileName: string);
    begin
      FFileName := FileName; //把得到的放到他该去的地方
      if FileName <> '' then
      begin
        DoLoadFile(FileName); 
      end;
    end;Procedure TChooseSongs.GetFileName; string;
    begin
      Result := FFileName;
    end;下面说PlaySongs地实现。
      

  18.   

    爱翔说的很对,但有一点我需要说明一下:作为Private可见性的成员方法或数据,对于申明在同一个Unit的其他类(不在同一继承链上)也是可以进行访问的,这就是友类!
      

  19.   

    我好像有点明白了,就拿我说的股票软件来说吧,改成这个样子是不是就对了?T用户,里面有买进股票和统计收支两个方法
    这两个方法都会跟数据库打交道,所以还有个T数据库,里面有各个query,还有对三个表格的读取方法使用中,当一个用户登陆后,我就创建一个T用户实例,用户做操作,我就调用相应的方法。当方法涉及到数据库操作时,我又会创建一个T数据库实例,再调用其中相应的方法我理解的对吗?这种编程感觉我还真是头一次体验,看来以前我从没oo过。 ~~~>_<~~~
      

  20.   

    代码随手写的,没有delphi的编译器,有错误见谅。我继续写。
      

  21.   

    我觉得自己越来越菜了,不行,一定要找个机会好好学学java。
      

  22.   

    TO zousoft:
    这么理解相当准确了。用户类承担用户类的责任,需要数据库时候,创建数据库实例,并把操作数据的一干责任交给该数据库实例。这样实现,是不是感觉类之间,责任很清晰明确?
      

  23.   

    To Zousoft  T个用户,你完全可以封装成一个类,里面提供两个方法,一个用来模拟用户发出的买入股票的动作,另外一个用来模拟统计收支这个工作。但我想说明的一点是,虽然这两个方法都需要和数据库去打交道,但没有必要T个用户就要对应T个数据库吧!所以个人一直认为类库结构的设计和库表结构的设计并没有绝对的直接关系,而且这种关系体现的几乎很不清晰!  对于一个完整的系统,虽然是使用面向对象的方法去分析,但最后的结构也可能是各种各样的!但我刚刚看了上面爱翔给出的那中类设计,个人认为很合理,首先创建一个抽象基类做为扩展的基础,然后在派生出一个被选择歌曲类,到这里就明白为什么需要那个抽象基类了,原因很简单,增加可扩展性!至于你提到的那个描述歌曲信息的类,我想对爱翔的设计提一点意见。这里可以先单独申明一个类,这个类包括一些数据成员,描述歌曲信息的各个方面,然后提供对这些成员的读写方法!这个类申明后,我们可以在歌曲的抽象基类同样定义个此类型(假设前面定义的描述歌曲信息的类为TSongInfo)的数据成员来直接使用,而不是将两个类分开处理!
      

  24.   

    huhu
    谢谢楼上,有点感觉了。不过平日编程很少真么做的看来要改改习惯。
      

  25.   

    ~~~~~~~~~~~~~~~~~~
    看看DELPHI提供給我們的控件
    ~~~~~~~~~~~~~~~~~~
    用類寫個代碼的人就能明白OO
    ~~~~~~~~~~~~~~~~~~
    越講越讓上不明白
    ~~~~~~~~~~~~~~~~~~
      

  26.   

    To Wdong18  任何程序中和数据库打交道的部分都是隶属于功能模块的,而我们的对象类产生的目的就是要将这些功能进行封装。所以说,和数据库直接接触的功能代码是应该放在我们产生的对象类中的,而不是你说的专门派生一个数据库实例(什么叫数据库实例?如何创建?)程序中所有的数据库实例的派生工作不应该开发人员来考虑,那是Delphi编译器的事情,除非我们对这些东西有特殊需求(比如内存考虑)!而所有的对象类所封装的功能也只能放在后台,前台则完全使用有IDE自动给我们产生的界面元素类来形成,对于功能和界面的关系,只需要简单的在前台调用后台对象类的实例的成员方法就可以了,这样就可以做到有效的UI分离!
      

  27.   

    哦,是的,如果针对成员的操作,是可以做一个比TChooseSongs在上一级的基类,叫TChooseSongs去继承它的对成员读写操作的过程。我只是简单的用代码说明一下对private里面数据的访问。具体代码实现还得总体的考虑。先把思路明确再说。
      

  28.   

    创建基类,进而扩展成子类,我认为这种方式,不是为了扩展基类的功能,而是为了完善基类的接口,是一种接口的多种实现方式。如果是为了扩展基类的功能,聚合方式可以取代继承方式。比如:
      T歌曲=class             //总的歌曲
      T分类歌曲=class(T歌曲) //分类的歌曲
    这种继承关系是必要的。点歌的时候,点歌器类,需要的是简单调用play功能,比如
    play(Classical),play(Pop)。如果点歌程序中出现了playClassical()和playPop()两个函数,就不合理了。这时候就需要继承T歌曲,派生TClassical歌曲,和TPop歌曲,分别实现两种不同的play.注意是两种不同的实现,并没有增添附加功能。
       T分类歌曲=class(T歌曲)
       T单曲=class(T分类歌曲)     //对单一歌曲的描述
    这里就有一点不合理的地方。按照本意,T单曲是“对单一歌曲的描述”,可以说,这是一种带描述信息的歌曲,比如附有歌词等等。显然T单曲相对于T歌曲,要有额外的字段和方法,来描述歌曲信息。我们先来看看采用继承的方式,有什么问题。
       T单曲=class(Tpop歌曲)//因为classical歌曲没有歌词,所以不用派生。
       private
          歌词;
       public
          get歌词;
          set歌词;
       end;
       因为T歌曲是祖先,所以不可否认,T单曲也是T歌曲,可惜他是个不孝子,因为违背了祖上的传统,加入了新时代的东西——歌词。这个东西,是祖先所没有的。
       然而,另一个类T点歌器,他是祖先T歌曲的老哥们儿,他们两个特熟悉。说的具体一些,T点歌器中,声明了T歌曲(声明的是祖先),并且调用了T歌曲的接口。那T单曲的get歌词该如何被T歌曲所认识呢?在T点歌器的眼里,T歌曲的子子孙孙都是T歌曲,为什么T单曲要多出一些功能呢?多出什么功能了?怎么调用?当然如果T歌曲家族只有一个T单曲这样的不肖子孙,还好办,大不了我T点歌器单独对待你好了(也就是重新声明一个T单曲,并且针对T单曲进行新的设计。)但如果每个子孙都像他这样,我想T点歌器一定会累吐血的。这一点,就是派生类添加新功能造成的问题。
       如果要增添新功能,我们宁可采用聚合的方式,而不是派生的方式。我们把T单曲改个名字叫T带歌词的歌曲,实现如下:
         T带歌词的歌曲=class
         private
             歌词;
             聚合歌曲:T歌曲;
         public
            play();
            get歌词();
            set歌词();
         end;
       implementation
         procedure T带歌词的歌曲。play();
         begin
           聚合歌曲。play();
         end;
       需要注意的是T带歌词的歌曲不是歌曲,但是兼容歌曲的接口.(如上所示)。通过:聚合歌曲。play()这种方式,来保证T带歌词的歌曲。play()和T歌曲.play()是相同的。这样子,T点歌器就不必再为T歌曲感到苦恼,如果他需要显示歌词的功能,简单地把T歌曲改成T带歌词的歌曲就可以了。
    上面所述,概括地说,就是使用聚合而不是继承来扩展接口。
      

  29.   

    To FrameSniper:
    我想FrameSniper一定是误解我的意思了,你是不是说TDataModule就是后台呢?我一般把数据库作为后台考虑,而不是把TDataModule作为后台考虑。也许对于一个好的数据库设计,我在TDataModule中就什么都不用做了。但是有时候确实需要用到TDataBase这样的东东,特别是面向对象的设计过程。我曾经需要做关系数据库到层次型数据的相互转换,这个是程序所必须的且无法在数据库后台实现。(我不知道后台数据库有没有面向对象的设计方法,还望指教。)所以,我曾经设计了一个TDataBase,提供SaveToDatabase函数,实际功能是转型,把一个树形结构转化成表结构。至于那些很底层的东西,当然是靠Delphi完成了。
      

  30.   

    to   reallike(认真学习Cpp用Cpp考虑delphi)
    这算什么bug啊,你既然用了它的子类,当然可以访问private。如果你的儿子都不能拿你们家的东西,那就不算儿子了……private是防止其他类来访问。当然不能阻止你的子类继承这个。
       
    这段话对private的描述有点问题。我不知道Delphi中是不是这样,在C++中,private表示只能被其自身类调用.他的派生类是不能调用的,但是这个private不管是成员函数还是成员数据对他的派生类来说是现实存在,可是是不可见的.如果想在派生类中调用的话,用protected关键字.
      

  31.   

    to zousoft(凶狠汤)T用户,里面有买进股票和统计收支两个方法
    这两个方法都会跟数据库打交道,所以还有个T数据库,里面有各个query,还有对三个表格的读取方法使用中,当一个用户登陆后,我就创建一个T用户实例,用户做操作,我就调用相应的方法。当方法涉及到数据库操作时,我又会创建一个T数据库实例,再调用其中相应的方法*****************************
    其本同意这样的做法,记得我在上面已经表述过,这里还有个类需要添加,那就是记录类.这个类是作为在用户类和数据库类传递数据所用的,这个类应该有些其本的数据检查等等功能.
      

  32.   

    不好意思,偶不知道这是delphi版,随便写了写.不要笑我
      

  33.   

    面向对象最大的好处是和现实比较接近。  所以我们分析的时候先从用户的角度出发,分出最抽象的几个对象。上面的例子说的歌曲都是最底层的具体数据描述层了。
      
      实现用类封装,而我们在分析系统时更要用面象对象的思想。
      T单个歌曲
       private
        ISBN
        名称
        类型
        歌词
        歌手
        ....................
        public 
         property PLay
         property Stop
        
      T歌曲列表
        private
          FItes:Array of T单个歌曲    public
          property Add
          Property Del
          Property Update
          Property Items[Index:integer]:T单个歌曲 
          property Find
          property GroupBy(AISBN)
          Property GroupBy(NAME)
          Property GroupBy(类型)
          Property GroupBy(.......)
        published
      end;歌的分类情况根据实现操作可以单独保存出来,不用每一次都去分类。
    有了这个基本的类,其它的操作都是以这为基础的。 要游泳去了,明天在聊。
        
         
      

  34.   

    To ZyxIp(绝望中...) :
    结构确实很清晰,体现了面向对象封装的思想。property应该是procedure吧,还是另有原因?
      

  35.   

    晕 @_@ 弱了,犯这种错误  上面Public下的全是过程Procedure或函数Function  上面有了这个最基本的对象,其它的就可以根据现实中的操作情况来定义了。将变化最少的业务单独封装,变化较多的业务用较多的配置文件来实现,可以实现不同的业务规则。
     
      返正思想是要有,但具体情况要具体对待,是在动态中求平衡的,有时为了系统实现方式的统一结构的完美,就要牺牲一些编程的方便性(比如全局变量);当然如果会对用户的操作有较大的影响,也会用一些怪异的实现方式,在不影响用户使用的前提下我倾向于实现的统一,对称,完美。
      
      一个系统是一棵树,只有一个起点和一个终点,从上到下有层次,没有游离在外部的东西,伸手从上到下捋下去能到底。(形容的也许不恰当)  明天在来听听大家的想法。
       
      今天刚换的水,就我们三个人,我马上就学会游泳了,爽。
      

  36.   


    各种歌曲文件的格式迥异,无法一下子说明表达。Mepg4的,DVD的,MP3的,real格式的,还有微软发布的一些格式。等等等。这个真得有点麻烦,而且还有其他的麻烦,比如说管理方面。嘿嘿,不怕,我们有派生继承这些,然后具体实现。假设是DVD点歌那很简单,就是TChooseDVDSongs = Class(TChooseSongs)
    protected
      DoLoadFile(FileName: string); override;
    public
      procedure PlaySongs(FileName: string): boolean; override;
    end;然后,实现具体的有关DVD形式歌曲的的播放,如果有其他的就扩展加入。嗯,好了,到现在,实现了播放。但是,还有选择呢。嘿嘿,基类、派生类都在不断的完善,上面写的仅仅是个初稿。既然叫choose song仅仅有Play song那还不叫choose,既然叫选择,那就明确目标,问问自己:选择什么?选择歌曲。
    为什么要选择?播放呗。
    如何作出选择? …… 哈哈,问到点子上了,好,关键是如何作出选择。歌曲多着呢,管理困难吗?不困难,我们有强大的数据库,合理的子目录。在乎这个?我说:NO!上面所说的给歌曲加上类?T歌曲 = class?我不敢用……哈,不敢苟同,不是什么事情都需要类的,那会效率低下何必呢?建好数据库来管理,是很轻松的事情。来,分析一下目标,我们的歌曲。分析好了才能做出选择。歌啊,在上古时代就由劳动人民发明了…… (挨了一板砖)NND,谁扔我。(FS大叫:奶奶个雄不是叫你小子解释歌是啥玩艺的)。:(俺就是啰嗦没有办法。
      

  37.   

    歌曲的格式是多,但每一种歌都会有相应的Play方法,会根据歌的类型不同自动调用相应的方法,如果只是播放时调用的解码器不同,没有必要将每一种格式都定义成一子类,就算是定义成了子类也要充分利用多态性。  一个点歌系统肯定是不论是什么格式最后用户操作的方式是一样的,也只是查找到相应歌播放,灵活性在于给用户提供多种歌曲的分类方式。我想应是先就分好类,将分类结果保存起来,点歌时根据分类结果直接找到播放。只有在维护歌曲列表时在重新分类。   点歌应是一个简单的系统,根本用不着定义多个类。   还有,我知道,你的MM 19 岁
      

  38.   

    上面看了这么多,感谢 FrameSniper(§绕瀑游龙§) ,reallike(认真学习Cpp用Cpp考虑delphi) ,ZyxIp(绝望中...) ,wdong18(东东) 及其他大哥的精彩贴子。具体的说我应该是懂了一些。前两天休息,所以没来得及回贴,不好意思。
    看各位大哥的发言,认为在不偏离主题的情况下,有必要说明一下点歌系统的基本业务和我开贴内容。一般来说点歌系统有纯软件实现和硬件辅助实现的两种。我说的基本上是后一种。
    点歌系统一般分成好几个部分。歌曲编辑部分主要由另一独立的程序来完成。
    主要一部分则完成歌曲显示及播放。现在讨论的是后一部分。所以只会读取相应的歌曲记录。不会对歌曲数据进行相应的增删改。所以前台程序的功能主要就是实现从数据库里读入歌曲,然后提供多种检索歌曲的方法。包括对歌曲的分类等等(分类的信息由后台定义)播放则是由硬件提供的相应的API提供,其实前台功能很简单。至于我的定义:
       T点歌钮=class(Tbutton)  //多加些属性
       因为需要实现换肤及自定义按钮功能等等所以才定义它。
       
       T歌曲=class             //总的歌曲
       我想应该是从歌曲库从里读出的所有歌曲,应该包括读取歌曲,关闭歌曲库的方法,以及歌曲总数等其它属性。
       
       T分类歌曲=class(T歌曲)    //分类的歌曲
       从总的歌曲里面继承下来,应该包括分类属性,分类条件属性,分类歌曲数等等属性及读取分类歌曲等方法。
       T单曲=class(T分类歌曲)     //对单一歌曲的描述
       从分类歌曲里面继承下来,包括播放,暂停,声道切换,停唱,循环,等等操作方法,以及该单曲信息属性及该单曲当前状态属性等等。
     
       具体怎么实现不谈,只是说按照这种业务用面向对象的方法来这样定义类好不好?到目前为止,所有的贴子里只有 wdong18(东东) 基本认同我。至于怎么样把歌曲从数据库里面读出来显示到LISTVIEW里我想应该是先调用“T歌曲”里面的读取歌曲的方法。然后再根据“T分类歌曲”分类歌曲属性,再调用显示分类歌曲的方法吧。如果用户选中歌曲,T单曲里面的相应方法来播放它。  不知道我这样想的对不对?请各位大哥讨论指正!          在此谢过
      

  39.   

    接受ZyxIp(绝望中...) 的想法:  将T歌曲和T分类歌曲合并:T歌曲
       private
        分类歌曲总数
        分类条件
        分类名
        ....................
          function LoadSong;          //根据分类条件从数据库读取分类歌曲
          function ShowSong;          //显示相应歌曲
        .......................
        这样可以了吧?
      

  40.   

    对于用户来说他只是选择一种分类方式然后从中选一首歌。
     
      你的  T单曲=class(T分类歌曲) 我觉得很是奇怪,子类应是父类的扩展,父类应处于更抽象的一层,而你这样定义是什么意思??现实的包含关系并不对应类的层次。  分类只是一个索引一样的东西,T单曲才是最终是操作的实体。单曲的存在与分类,如何分类并没有什么关系,所以T单曲和T分类歌曲根本就不是一类,并不存在什么继承关系
       
      还有你的 T分类歌曲=class(T歌曲)  ,从根本上来说就是相同的,所有的歌曲也是分类歌曲的一种,你的意思是分类歌曲是按歌手,姓别等条件分类的。那全部歌曲是按无条件分类的,它们也不存在什么继承关系。
      

  41.   

    唔,对哇,所以我把分类歌曲和歌曲合并成了歌曲一类   T歌曲=class
       T单曲=class(T歌曲)   我主要是想歌曲包含的是大类的歌曲,而单曲则是这大类里面的一个。
      “现实的包含关系并不对应类的层次”?
      

  42.   

    reallike(认真学习Cpp用Cpp考虑delphi) 
    接着写啊 收获很大,现在才知道OO原来是这样,呵呵
    期待中。
    ZyxIp(绝望中...) wdong18(东东)  FrameSniper(§绕瀑游龙§) 
    你们的帖子也很精彩,受益非浅
      

  43.   

    to reallike(认真学习Cpp用Cpp考虑delphi) 好,咱们回到他的点歌系统,既然是点歌系统,那就要从点歌入手。
    尽管看上去点歌确实简单,好像不值得做似的。但是它是核心。它才是最重要的。
    因为要做的是“点”歌。而不是“管”歌,不是歌库,更不是点歌按钮……
    如果从界面,从歌曲入手,那就出现实质性的失误,他们仅仅是细节,
    尽管从技术含量来说好像比点歌来的困难,但是要分清主次。点,是通俗的说法,也就是说作出一种选择。当东西多了的时候,选择还是比较困难的。但是我们选择之后要做什么呢?播放,对,实质其实还是播放歌曲。所以我在点歌上面写下了,播放。哦,好了,我们所有的工作其实是为了播放而作的。所以,我要建立一个抽象的基类,我在点歌左边写下了TChooseSongs
    哦,他的第一个过程一定是个public的,因为它就是最重要的播放。
    Procedure PlaySongs(FileName: String);Boolean; virtual; abstract;为什么是虚函数后面会解释。
    哦,文件名应该是被保护的,所以FFileName应该在private里面所以简单的基类建立了。如果有其他的功能扩充再说。TChooseSongs = class
    private 
      FFileName: string;
    public
      Procedure PlaySongs(FileName: String);Boolean; virtual; abstract;
    end;哦?如何访问FFileName呢?嗯,对了,我们需要一个方法,一个函数来传递FFileName。OK,我们就用Template Method来建立这个类,去得到FFileName。还需要一个过程来得到FFileName,不能直接来用。TChooseSongs = class
    private
      FFileName: string;
    protected
      procedure DoLoadFile(FileName: string); Virtual; abstract;
    private
      Procedure LoadFile(FileName: string);
      Procedure GetFileName; string;
      Procedure PlaySongs(FileName: String);Boolean; virtual; abstract;
    end;template mothed就是如此了,很简单的LoadFile的代码实现。Procedure TChooseSongsLoadFile(FileName: string);
    begin
      FFileName := FileName; //把得到的放到他该去的地方
      if FileName <> '' then
      begin
        DoLoadFile(FileName); 
      end;
    end;Procedure TChooseSongs.GetFileName; string;
    begin
      Result := FFileName;
    end;
    各种歌曲文件的格式迥异,无法一下子说明表达。Mepg4的,DVD的,MP3的,real格式的,还有微软发布的一些格式。等等等。这个真得有点麻烦,而且还有其他的麻烦,比如说管理方面。嘿嘿,不怕,我们有派生继承这些,然后具体实现。假设是DVD点歌那很简单,就是TChooseDVDSongs = Class(TChooseSongs)
    protected
      DoLoadFile(FileName: string); override;
    public
      procedure PlaySongs(FileName: string): boolean; override;
    end;然后,实现具体的有关DVD形式歌曲的的播放,如果有其他的就扩展加入。嗯,好了,到现在,实现了播放。但是,还有选择呢。嘿嘿,基类、派生类都在不断的完善,上面写的仅仅是个初稿。既然叫choose song仅仅有Play song那还不叫choose,既然叫选择,那就明确目标,问问自己:选择什么?选择歌曲。
    为什么要选择?播放呗。
    如何作出选择? …… 哈哈,问到点子上了,好,关键是如何作出选择。歌曲多着呢,管理困难吗?不困难,我们有强大的数据库,合理的子目录。在乎这个?我说:NO!上面所说的给歌曲加上类?T歌曲 = class?我不敢用……哈,不敢苟同,不是什么事情都需要类的,那会效率低下何必呢?建好数据库来管理,是很轻松的事情。=================================================================================
      我真的有认真看你回复的贴子,只是我太笨了,还请谅解,我觉得对点歌系统这个业务来说,你和ZyxIp(绝望中...) 对于类的划分思想大致是一样的吧?(有不同吗?能指出来吗?)  我只是觉得我   T歌曲=class
       T单曲=class(T歌曲)  这样划分为什么不好哦?就是这点不明白。我这样分是不是有违面向对象的观点?还是可以这样分只是多余?我觉得T歌曲类做T歌曲类做的事,T单曲类做T单曲类做的事。还是我对面向对象的观点又错了?(或许你们已经回答了这些问题,但是能不能再通俗一点的讲一下?因为,我比较笨) ZyxIp(绝望中...) 说:
    分类只是一个索引一样的东西,T单曲才是最终是操作的实体。单曲的存在与分类,如何分类并没有什么关系,所以T单曲和T分类歌曲根本就不是一类,并不存在什么继承关系
    =================================================================================
    我觉得T歌曲类并不仅仅是一个索引一样的东西哇,它有好多事要做呢。T单曲是T歌曲众多歌曲里面的一首歌曲哇?对于单曲来讲必须要做自已独特的事情(播放暂停等等),为什么不存在什么继承关系呢?
      

  44.   

    其实更多的你只是着重去怎么实现,而我想知道怎么样去归类?是,歌曲的分类在数据库里面有相应的字段去描述。选择怎么样的分类只是SQL语句的不同。同样,播放只需要调用简单的API,对卡的操作也已经全部封装起来。这些都不是我要关心的,我只是想为什么要这样分类?
      

  45.   

    晕,给歌曲分类还用得着类吗?没错,你做得没有错。但是你这种做法合适吗?效率有吗?我不知道你用类管理歌曲有什么意义。我看不出任何意义,你分一个目录,然后用getdir找到它,然后把文件加载到播放器就可以了。甚至可以把建立好的路径放到数据库里面,然后通过检索找到合适的。T歌曲,有意义吗?我现在问你。不能说用高射炮打蚊子,真的是大材小用
      

  46.   

    晕,给歌曲分类还用得着类吗?没错,你做得没有错。但是你这种做法合适吗?效率有吗?我不知道你用类管理歌曲有什么意义。我看不出任何意义,你分一个目录,然后用getdir找到它,然后把文件加载到播放器就可以了。甚至可以把建立好的路径放到数据库里面,然后通过检索找到合适的。T歌曲,有意义吗?我现在问你。不能说用高射炮打蚊子,真的是大材小用
      

  47.   

    to reallike(认真学习Cpp用Cpp考虑delphi)  你的: 全局变量的使用与面向对象的讨论。 一直在看呀。
     
      你上面的TChooseDVDSongs = Class(TChooseSongs)也看了,我觉得要只是放出声的话分到单曲也行了,用一个Play放所有类型
      Case SongStyle of
       DVD:;
       VCD:;
       MP3:;
       .....
      end;
    如果每一种格式不只是Play 的方式不同,还有其它的更多的不同的可以将这个类分的更细一些,但也要充分利用多态性。
      
      To  PrettyMurphy(土豆)  你的
          T歌曲=class
          T单曲=class(T歌曲)   我觉得还是不对头,你的 T单曲 并不是 T歌曲 的扩展,根本就不是继承关系,现实的这种“包含”并不对应类的层次 ,面向对象中“归类”是重要步骤,类描述了具有相似性质的一组对象。  你的 T歌曲=class 只是一个单曲集合,如下定义会更明白一些。     T歌曲Item=Class
          ...
         end; 
     如有必要可能给每个类型的歌定义一个类
         TMP3歌曲=Class(T歌曲Item)
         ...
         end;
        TDVD歌曲=Class(T歌曲Item)
         ...
         end;下面是管理所有歌的类
     
         T歌曲Items=Class
          Private 
            FItems:Array of T歌曲Item;
          public
            property Items[Index:integer]: T歌曲Item +Ctrl_Shift_c;
          end;
      

  48.   

    唉,ZyxIp(绝望中...) 我稍一没有讲为什么不做选择,而是用派生类,你不理解…… 你果然也这么做。用Case,你以为我没有想?我早就想到了,但是不合适。那不是多态!用Case也提高不了效率,而且会把代码弄得冗长,还得分出许多Play的过程来。我总是从效率入手。效率在我眼里是第一位的。
      

  49.   

    给歌曲分类根本就不用TXXX的,而且也不用每一次用户选择分类方式的时候你才用SQL分类.在给数据库录完数据后一次就分好了,将各种分类的结果保存起来。如用XML文件描述是这样子。
    <按歌手分>
      <歌手1>
        <第1首 名字="给用户显示的名称" 位置="路径或数据库中记录的编程">
        <第2首 名字="" 位置="">
      </歌手1>
      <歌手2>
        <第1首 名字="" 位置="">
        <第2首 名字="" 位置="">
      </歌手2>
       <歌手3>
        <第1首 名字="" 位置="">
        <第2首 名字="" 位置="">
      </歌手3> 
    </按歌手分>
    <按字数分>
      <1字歌>
        <第1首 名字="" 位置="">
        <第2首 名字="" 位置="">
        
      </1字歌>
      <2字歌>
       <第1首 名字="" 位置="">
        <第2首 名字="" 位置="">
      </2字歌>
      <3字歌>
        <第1首 名字="" 位置="">
        <第2首 名字="" 位置="">
      </3字歌></按字数分>
    ................
     
       这样是冗于,但比你每次到数据库中查要快,而且就算你有10万首歌给用户提供10种分类方式,你查找时先在10个分类中找出对应的分类,然后将下面的数据顺序显示就可以了。
      点歌系统太小了,我看根本体现不出面向对象编程的好处,它的难点在于技术上如何调用多种解码器来显示。在系统结构分析上就没有什么东西。
      

  50.   

    to reallike(认真学习Cpp用Cpp考虑delphi) 
    但是你这种做法合适吗?效率有吗?我不知道你用类管理歌曲有什么意义。我看不出任何意义,你分一个目录,然后用getdir找到它,然后把文件加载到播放器就可以了。甚至可以把建立好的路径放到数据库里面,然后通过检索找到合适的。
    ====================================================================
    分类的结果是必须要显示出来的。因为用户只会去选择分类歌曲中的一首歌曲。
    而且为了方便以后维护,每个歌曲文件不会固定存放哪个目录,只需与数据库中路径相对应即可。
    用getdir找就等于在数据库里找。找出来的结果RECORDSET是必须要显示给用户看的。
    这样的话,分类找记录的函数或过程应该放在哪里?做成公用模块?那样也可以完全不要创建类哇。既然你的目的是点歌,那你就说点歌。可是你到现在都没有作任何点歌的措施。
    ==================================================================
    我想,点歌的方法应该在“T单曲类”里面的方法里得到体现。包括播放及其它操作。to ZyxIp(绝望中...) 我觉得还是不对头,你的 T单曲 并不是 T歌曲 的扩展,根本就不是继承关系,现实的这种“包含”并不对应类的层次 ,面向对象中“归类”是重要步骤,类描述了具有相似性质的一组对象。
    ===============================================================================
    我想我是错了,ZyxIp(绝望中...) 说的对,T歌曲 只是单曲的组合已经,不是继承。但是又回到了同to reallike(认真学习Cpp用Cpp考虑delphi) 一样的结论?找出来的结果RECORDSET是必须要显示给用户看的。
    这样的话,分类找记录的函数或过程应该放在哪里?做成公用模块?
      

  51.   

    reallike(认真学习Cpp用Cpp考虑delphi) 别罗。再讨论讨论罗。教别人同时也是在提高自已嘛。:)
      

  52.   

    好吧,既然是这么想,点歌是那么实现的。你就那么做好了。我看我的cpp primer去了哦。:〉
      

  53.   

    好吧,既然是这么想,点歌是那么实现的。你就那么做好了。我看我的cpp primer去了哦。:〉
      

  54.   

    我说的这些话好像没有人看:
    我只是针对楼顶的对项目的分析的一些不恰当做法提出我的一些看法。面向对象,首先就是考虑面向的“对象”是什么,自己面向的对象都不明确,怎么在一个项目里面有针对性地作为?重点不明确,没有核心,会造成一种混乱。把对象树立好了,再谈面向。如果对象树立不正确,再谈面向同样是空谈。围绕对象来操作,才是面向对象的一个本质。之后才是使用软件工程之类的技巧和经验。对于这个问题,我打个比方,打个大一点的比方。可能FS从来没有想,但是我想了。我们的人生,我们的人生所要面向的对象,也就是我们的人生目标你明确了没有?人生目标明确再说逐步实施的细节,里面可能有坎坷,可能有幸福。但是都是细节都是为我们的目标而服务的。但是大前提,就是找到对象。再打一个比方,最近FS失恋,我就拿这个来打比方。FS你是否考虑你的对象——嘿嘿,还真是对象——她到底是什么形象?什么素质?你有没有目标,也就是对象?你是否真地树立了合理的对象?假如你树立好了,中间任何不择手段的方法,仅仅是手段。:〉好,咱们回到他的点歌系统,既然是点歌系统,那就要从点歌入手。尽管看上去点歌确实简单,好像不值得做似的。但是它是核心。它才是最重要的。因为要做的是“点”歌。而不是“管”歌,不是歌库,更不是点歌按钮……如果从界面,从歌曲入手,那就出现实质性的失误,他们仅仅是细节,尽管从技术含量来说好像比点歌来的困难,但是要分清主次。好了,明确目标我再和FS讨论具体的实现。
    既然没有人看,那也就算了。
      

  55.   

    用Case 当然不是多态,可我们也不能因为DvD,Mp3,rm这些存在,在这个系统中可以用多态而去用多态,你说的效率是指什么效率??从空间和资源上来考虑还是从编程方便性维护性上考虑?就算用多态也并不能提高执行效率。
      

  56.   

    谢谢ZyxIp(绝望中...) , reallike(认真学习Cpp用Cpp考虑delphi) ,wdong18(东东)  ,FrameSniper(§绕瀑游龙§) 及其他各位大哥。我想我应该再去看书。先到这吧。谢谢!